diff --git a/core/encoding/cel/cel.odin b/core/encoding/cel/cel.odin index fe36978c2..ead61c05e 100644 --- a/core/encoding/cel/cel.odin +++ b/core/encoding/cel/cel.odin @@ -106,11 +106,11 @@ create_from_tokenizer :: proc(t: ^Tokenizer) -> (^Parser, bool) { p := new(Parser); for { tok := scan(t); - if tok.kind == Kind.Illegal { + if tok.kind == .Illegal { return p, false; } append(&p.tokens, tok); - if tok.kind == Kind.EOF { + if tok.kind == .EOF { break; } } @@ -120,7 +120,7 @@ create_from_tokenizer :: proc(t: ^Tokenizer) -> (^Parser, bool) { } if len(p.tokens) == 0 { - tok := Token{kind = Kind.EOF}; + tok := Token{kind = .EOF}; tok.line, tok.column = 1, 1; append(&p.tokens, tok); return p, true; @@ -134,8 +134,8 @@ create_from_tokenizer :: proc(t: ^Tokenizer) -> (^Parser, bool) { p.dict_stack = make([dynamic]^Dict, 0, 4); append(&p.dict_stack, &p.root); - for p.curr_token.kind != Kind.EOF && - p.curr_token.kind != Kind.Illegal && + for p.curr_token.kind != .EOF && + p.curr_token.kind != .Illegal && p.curr_token_index < len(p.tokens) { if !parse_assignment(p) { break; @@ -147,7 +147,7 @@ create_from_tokenizer :: proc(t: ^Tokenizer) -> (^Parser, bool) { destroy :: proc(p: ^Parser) { destroy_value :: proc(value: Value) { - switch v in value { + #partial switch v in value { case Array: for elem in v do destroy_value(elem); delete(v); @@ -287,7 +287,7 @@ unquote_char :: proc(str: string, quote: byte) -> (r: rune, multiple_bytes: bool unquote_string :: proc(p: ^Parser, t: Token) -> (string, bool) { - if t.kind != Kind.String { + if t.kind != .String { return t.lit, true; } s := t.lit; @@ -368,8 +368,8 @@ expect_operator :: proc(p: ^Parser) -> Token { fix_advance :: proc(p: ^Parser) { for { - switch t := p.curr_token; t.kind { - case Kind.EOF, Kind.Semicolon: + #partial switch t := p.curr_token; t.kind { + case .EOF, .Semicolon: return; } next_token(p); @@ -377,7 +377,7 @@ fix_advance :: proc(p: ^Parser) { } copy_value :: proc(value: Value) -> Value { - switch v in value { + #partial switch v in value { case Array: a := make(Array, len(v)); for elem, idx in v { @@ -407,79 +407,79 @@ lookup_value :: proc(p: ^Parser, name: string) -> (Value, bool) { parse_operand :: proc(p: ^Parser) -> (Value, Pos) { tok := p.curr_token; - switch p.curr_token.kind { - case Kind.Ident: + #partial switch p.curr_token.kind { + case .Ident: next_token(p); v, ok := lookup_value(p, tok.lit); if !ok do error(p, tok.pos, "Undeclared identifier %s", tok.lit); return v, tok.pos; - case Kind.True: + case .True: next_token(p); return true, tok.pos; - case Kind.False: + case .False: next_token(p); return false, tok.pos; - case Kind.Nil: + case .Nil: next_token(p); return Nil_Value{}, tok.pos; - case Kind.Integer: + case .Integer: next_token(p); return strconv.parse_i64(tok.lit), tok.pos; - case Kind.Float: + case .Float: next_token(p); return strconv.parse_f64(tok.lit), tok.pos; - case Kind.String: + case .String: next_token(p); str, ok := unquote_string(p, tok); if !ok do error(p, tok.pos, "Unable to unquote string"); return string(str), tok.pos; - case Kind.Open_Paren: - expect_token(p, Kind.Open_Paren); + case .Open_Paren: + expect_token(p, .Open_Paren); expr, _ := parse_expr(p); - expect_token(p, Kind.Close_Paren); + expect_token(p, .Close_Paren); return expr, tok.pos; - case Kind.Open_Bracket: - expect_token(p, Kind.Open_Bracket); + case .Open_Bracket: + expect_token(p, .Open_Bracket); elems := make([dynamic]Value, 0, 4); - for p.curr_token.kind != Kind.Close_Bracket && - p.curr_token.kind != Kind.EOF { + for p.curr_token.kind != .Close_Bracket && + p.curr_token.kind != .EOF { elem, _ := parse_expr(p); append(&elems, elem); - if p.curr_token.kind == Kind.Semicolon && p.curr_token.lit == "\n" { + if p.curr_token.kind == .Semicolon && p.curr_token.lit == "\n" { next_token(p); - } else if !allow_token(p, Kind.Comma) { + } else if !allow_token(p, .Comma) { break; } } - expect_token(p, Kind.Close_Bracket); + expect_token(p, .Close_Bracket); return Array(elems[:]), tok.pos; - case Kind.Open_Brace: - expect_token(p, Kind.Open_Brace); + case .Open_Brace: + expect_token(p, .Open_Brace); dict := Dict{}; append(&p.dict_stack, &dict); defer pop(&p.dict_stack); - for p.curr_token.kind != Kind.Close_Brace && - p.curr_token.kind != Kind.EOF { + for p.curr_token.kind != .Close_Brace && + p.curr_token.kind != .EOF { name_tok := p.curr_token; - if !allow_token(p, Kind.Ident) && !allow_token(p, Kind.String) { - name_tok = expect_token(p, Kind.Ident); + if !allow_token(p, .Ident) && !allow_token(p, .String) { + name_tok = expect_token(p, .Ident); } name, ok := unquote_string(p, name_tok); if !ok do error(p, tok.pos, "Unable to unquote string"); - expect_token(p, Kind.Assign); + expect_token(p, .Assign); elem, _ := parse_expr(p); if _, ok2 := dict[name]; ok2 { @@ -488,13 +488,13 @@ parse_operand :: proc(p: ^Parser) -> (Value, Pos) { dict[name] = elem; } - if p.curr_token.kind == Kind.Semicolon && p.curr_token.lit == "\n" { + if p.curr_token.kind == .Semicolon && p.curr_token.lit == "\n" { next_token(p); - } else if !allow_token(p, Kind.Comma) { + } else if !allow_token(p, .Comma) { break; } } - expect_token(p, Kind.Close_Brace); + expect_token(p, .Close_Brace); return dict, tok.pos; } @@ -504,13 +504,13 @@ parse_operand :: proc(p: ^Parser) -> (Value, Pos) { parse_atom_expr :: proc(p: ^Parser, operand: Value, pos: Pos) -> (Value, Pos) { loop := true; for operand := operand; loop; { - switch p.curr_token.kind { - case Kind.Period: + #partial switch p.curr_token.kind { + case .Period: next_token(p); tok := next_token(p); - switch tok.kind { - case Kind.Ident: + #partial switch tok.kind { + case .Ident: d, ok := operand.(Dict); if !ok || d == nil { error(p, tok.pos, "Expected a dictionary"); @@ -531,13 +531,13 @@ parse_atom_expr :: proc(p: ^Parser, operand: Value, pos: Pos) -> (Value, Pos) { operand = nil; } - case Kind.Open_Bracket: - expect_token(p, Kind.Open_Bracket); + case .Open_Bracket: + expect_token(p, .Open_Bracket); index, index_pos := parse_expr(p); - expect_token(p, Kind.Close_Bracket); + expect_token(p, .Close_Bracket); - switch a in operand { + #partial switch a in operand { case Array: i, ok := index.(i64); if !ok { @@ -587,22 +587,22 @@ parse_atom_expr :: proc(p: ^Parser, operand: Value, pos: Pos) -> (Value, Pos) { parse_unary_expr :: proc(p: ^Parser) -> (Value, Pos) { op := p.curr_token; - switch p.curr_token.kind { - case Kind.At: + #partial switch p.curr_token.kind { + case .At: next_token(p); - tok := expect_token(p, Kind.String); + tok := expect_token(p, .String); v, ok := lookup_value(p, tok.lit); if !ok do error(p, tok.pos, "Undeclared identifier %s", tok.lit); return parse_atom_expr(p, v, tok.pos); - case Kind.Add, Kind.Sub: + case .Add, .Sub: next_token(p); // TODO(bill): Calcuate values as you go! expr, pos := parse_unary_expr(p); - switch e in expr { - case i64: if op.kind == Kind.Sub do return -e, pos; - case f64: if op.kind == Kind.Sub do return -e, pos; + #partial switch e in expr { + case i64: if op.kind == .Sub do return -e, pos; + case f64: if op.kind == .Sub do return -e, pos; case: error(p, op.pos, "Unary operator %s can only be used on integers or floats", op.lit); return nil, op.pos; @@ -610,7 +610,7 @@ parse_unary_expr :: proc(p: ^Parser) -> (Value, Pos) { return expr, op.pos; - case Kind.Not: + case .Not: next_token(p); expr, _ := parse_unary_expr(p); if v, ok := expr.(bool); ok { @@ -625,7 +625,7 @@ parse_unary_expr :: proc(p: ^Parser) -> (Value, Pos) { value_order :: proc(v: Value) -> int { - switch _ in v { + #partial switch _ in v { case bool, string: return 1; case i64: @@ -641,13 +641,13 @@ match_values :: proc(left, right: ^Value) -> bool { return match_values(right, left); } - switch x in left^ { + #partial switch x in left^ { case: right^ = left^; case bool, string: return true; case i64: - switch y in right^ { + #partial switch y in right^ { case i64: return true; case f64: @@ -656,7 +656,7 @@ match_values :: proc(left, right: ^Value) -> bool { } case f64: - switch y in right { + #partial switch y in right { case f64: return true; } @@ -671,59 +671,59 @@ calculate_binary_value :: proc(p: ^Parser, op: Kind, a, b: Value) -> (Value, boo match_values(&x, &y); - switch a in x { + #partial switch a in x { case: return x, true; case bool: b, ok := y.(bool); if !ok do return nil, false; - switch op { - case Kind.Eq: return a == b, true; - case Kind.NotEq: return a != b, true; - case Kind.And: return a && b, true; - case Kind.Or: return a || b, true; + #partial switch op { + case .Eq: return a == b, true; + case .NotEq: return a != b, true; + case .And: return a && b, true; + case .Or: return a || b, true; } case i64: b, ok := y.(i64); if !ok do return nil, false; - switch op { - case Kind.Add: return a + b, true; - case Kind.Sub: return a - b, true; - case Kind.Mul: return a * b, true; - case Kind.Quo: return a / b, true; - case Kind.Rem: return a % b, true; - case Kind.Eq: return a == b, true; - case Kind.NotEq: return a != b, true; - case Kind.Lt: return a < b, true; - case Kind.Gt: return a > b, true; - case Kind.LtEq: return a <= b, true; - case Kind.GtEq: return a >= b, true; + #partial switch op { + case .Add: return a + b, true; + case .Sub: return a - b, true; + case .Mul: return a * b, true; + case .Quo: return a / b, true; + case .Rem: return a % b, true; + case .Eq: return a == b, true; + case .NotEq: return a != b, true; + case .Lt: return a < b, true; + case .Gt: return a > b, true; + case .LtEq: return a <= b, true; + case .GtEq: return a >= b, true; } case f64: b, ok := y.(f64); if !ok do return nil, false; - switch op { - case Kind.Add: return a + b, true; - case Kind.Sub: return a - b, true; - case Kind.Mul: return a * b, true; - case Kind.Quo: return a / b, true; - case Kind.Eq: return a == b, true; - case Kind.NotEq: return a != b, true; - case Kind.Lt: return a < b, true; - case Kind.Gt: return a > b, true; - case Kind.LtEq: return a <= b, true; - case Kind.GtEq: return a >= b, true; + #partial switch op { + case .Add: return a + b, true; + case .Sub: return a - b, true; + case .Mul: return a * b, true; + case .Quo: return a / b, true; + case .Eq: return a == b, true; + case .NotEq: return a != b, true; + case .Lt: return a < b, true; + case .Gt: return a > b, true; + case .LtEq: return a <= b, true; + case .GtEq: return a >= b, true; } case string: b, ok := y.(string); if !ok do return nil, false; - switch op { - case Kind.Add: + #partial switch op { + case .Add: n := len(a) + len(b); data := make([]byte, n); copy(data[:], a); @@ -732,12 +732,12 @@ calculate_binary_value :: proc(p: ^Parser, op: Kind, a, b: Value) -> (Value, boo append(&p.allocated_strings, s); return s, true; - case Kind.Eq: return a == b, true; - case Kind.NotEq: return a != b, true; - case Kind.Lt: return a < b, true; - case Kind.Gt: return a > b, true; - case Kind.LtEq: return a <= b, true; - case Kind.GtEq: return a >= b, true; + case .Eq: return a == b, true; + case .NotEq: return a != b, true; + case .Lt: return a < b, true; + case .Gt: return a > b, true; + case .LtEq: return a <= b, true; + case .GtEq: return a >= b, true; } } @@ -755,10 +755,10 @@ parse_binary_expr :: proc(p: ^Parser, prec_in: int) -> (Value, Pos) { } expect_operator(p); - if op.kind == Kind.Question { + if op.kind == .Question { cond := expr; x, _ := parse_expr(p); - expect_token(p, Kind.Colon); + expect_token(p, .Colon); y, _ := parse_expr(p); if t, ok := cond.(bool); ok { @@ -791,13 +791,13 @@ parse_expr :: proc(p: ^Parser) -> (Value, Pos) { expect_semicolon :: proc(p: ^Parser) { kind := p.curr_token.kind; - switch kind { - case Kind.Comma: + #partial switch kind { + case .Comma: error(p, p.curr_token.pos, "Expected ';', got ','"); next_token(p); - case Kind.Semicolon: + case .Semicolon: next_token(p); - case Kind.EOF: + case .EOF: // okay case: error(p, p.curr_token.pos, "Expected ';', got %s", p.curr_token.lit); @@ -811,17 +811,17 @@ parse_assignment :: proc(p: ^Parser) -> bool { return p.dict_stack[len(p.dict_stack)-1]; } - if p.curr_token.kind == Kind.Semicolon { + if p.curr_token.kind == .Semicolon { next_token(p); return true; } - if p.curr_token.kind == Kind.EOF { + if p.curr_token.kind == .EOF { return false; } tok := p.curr_token; - if allow_token(p, Kind.Ident) || allow_token(p, Kind.String) { - expect_token(p, Kind.Assign); + if allow_token(p, .Ident) || allow_token(p, .String) { + expect_token(p, .Assign); name, ok := unquote_string(p, tok); if !ok do error(p, tok.pos, "Unable to unquote string"); expr, _ := parse_expr(p); diff --git a/core/encoding/cel/token.odin b/core/encoding/cel/token.odin index a2bcb963a..6d6238014 100644 --- a/core/encoding/cel/token.odin +++ b/core/encoding/cel/token.odin @@ -137,7 +137,7 @@ kind_to_string := [len(Kind)]string{ }; precedence :: proc(op: Kind) -> int { - switch op { + #partial switch op { case Question: return 1; case Or: diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index f3d894f3f..4e4447143 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -40,7 +40,7 @@ marshal_arg :: proc(b: ^strings.Builder, v: any) -> Marshal_Error { ti := type_info_base(type_info_of(v.id)); a := any{v.data, ti.id}; - switch info in ti.variant { + #partial switch info in ti.variant { case Type_Info_Named: panic("Unreachable"); @@ -282,7 +282,7 @@ marshal_arg :: proc(b: ^strings.Builder, v: any) -> Marshal_Error { return false; } t := runtime.type_info_base(ti); - switch info in t.variant { + #partial switch info in t.variant { case runtime.Type_Info_Integer: switch info.endianness { case .Platform: return false; diff --git a/core/encoding/json/parser.odin b/core/encoding/json/parser.odin index 36a68f31c..8503edd98 100644 --- a/core/encoding/json/parser.odin +++ b/core/encoding/json/parser.odin @@ -70,7 +70,7 @@ parse_value :: proc(p: ^Parser) -> (value: Value, err: Error) { defer value.end = token_end_pos(p.prev_token); token := p.curr_token; - switch token.kind { + #partial switch token.kind { case Kind.Null: value.value = Null{}; advance_token(p); @@ -105,7 +105,7 @@ parse_value :: proc(p: ^Parser) -> (value: Value, err: Error) { case: if p.spec == Specification.JSON5 { - switch token.kind { + #partial switch token.kind { case Kind.Infinity: inf: u64 = 0x7ff0000000000000; if token.text[0] == '-' { diff --git a/core/encoding/json/types.odin b/core/encoding/json/types.odin index 036fe50b4..1c106d591 100644 --- a/core/encoding/json/types.odin +++ b/core/encoding/json/types.odin @@ -56,7 +56,7 @@ Error :: enum { destroy_value :: proc(value: Value) { - switch v in value.value { + #partial switch v in value.value { case Object: for key, elem in v { delete(key); diff --git a/core/encoding/json/validator.odin b/core/encoding/json/validator.odin index 17073f102..77339bbc3 100644 --- a/core/encoding/json/validator.odin +++ b/core/encoding/json/validator.odin @@ -91,28 +91,27 @@ validate_array :: proc(p: ^Parser) -> bool { validate_value :: proc(p: ^Parser) -> bool { token := p.curr_token; - using Kind; - switch token.kind { - case Null, False, True: + #partial switch token.kind { + case .Null, .False, .True: advance_token(p); return true; - case Integer, Float: + case .Integer, .Float: advance_token(p); return true; - case String: + case .String: advance_token(p); return is_valid_string_literal(token.text, p.spec); - case Open_Brace: + case .Open_Brace: return validate_object(p); - case Open_Bracket: + case .Open_Bracket: return validate_array(p); case: if p.spec == Specification.JSON5 { - switch token.kind { - case Infinity, NaN: + #partial switch token.kind { + case .Infinity, .NaN: advance_token(p); return true; } diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 80ff890c8..c03fbacdb 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -794,7 +794,7 @@ enum_value_to_string :: proc(val: any) -> (string, bool) { v.id = runtime.typeid_base(v.id); type_info := type_info_of(v.id); - switch e in type_info.variant { + #partial switch e in type_info.variant { case: return "", false; case runtime.Type_Info_Enum: get_str :: proc(i: $T, e: runtime.Type_Info_Enum) -> (string, bool) { @@ -857,7 +857,7 @@ fmt_enum :: proc(fi: ^Info, v: any, verb: rune) { } type_info := type_info_of(v.id); - switch e in type_info.variant { + #partial switch e in type_info.variant { case: fmt_bad_verb(fi, verb); case runtime.Type_Info_Enum: switch verb { @@ -898,7 +898,7 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") { return false; } t := runtime.type_info_base(ti); - switch info in t.variant { + #partial switch info in t.variant { case runtime.Type_Info_Integer: switch info.endianness { case .Platform: return false; @@ -912,7 +912,7 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") { byte_swap :: bits.byte_swap; type_info := type_info_of(v.id); - switch info in type_info.variant { + #partial switch info in type_info.variant { case runtime.Type_Info_Named: val := v; val.id = info.base.id; @@ -982,7 +982,7 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") { } fmt_bit_field :: proc(fi: ^Info, v: any, bit_field_name: string = "") { type_info := type_info_of(v.id); - switch info in type_info.variant { + #partial switch info in type_info.variant { case runtime.Type_Info_Named: val := v; val.id = info.base.id; @@ -1052,7 +1052,7 @@ fmt_opaque :: proc(fi: ^Info, v: any) { strings.write_byte(fi.buf, '{'); defer strings.write_byte(fi.buf, '}'); - switch in elem.variant { + #partial switch in elem.variant { case rt.Type_Info_Integer, rt.Type_Info_Pointer, rt.Type_Info_Float: fmt_value(fi, any{v.data, elem.id}, 'v'); case: @@ -1073,8 +1073,11 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { type_info := type_info_of(v.id); switch info in type_info.variant { + case runtime.Type_Info_Any: // Ignore + case runtime.Type_Info_Tuple: // Ignore + case runtime.Type_Info_Named: - switch b in info.base.variant { + #partial switch b in info.base.variant { case runtime.Type_Info_Struct: if verb != 'v' { fmt_bad_verb(fi, verb); @@ -1193,7 +1196,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { a := any{ptr, info.elem.id}; elem := runtime.type_info_base(info.elem); - if elem != nil do switch e in elem.variant { + if elem != nil do #partial switch e in elem.variant { case runtime.Type_Info_Array, runtime.Type_Info_Slice, runtime.Type_Info_Dynamic_Array, diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index afc92e345..931000a7c 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -331,7 +331,7 @@ Switch_Stmt :: struct { init: ^Stmt, cond: ^Expr, body: ^Stmt, - complete: bool, + partial: bool, } Type_Switch_Stmt :: struct { @@ -341,7 +341,7 @@ Type_Switch_Stmt :: struct { tag: ^Stmt, expr: ^Expr, body: ^Stmt, - complete: bool, + partial: bool, } Branch_Stmt :: struct { diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index a233db068..15545dca1 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -390,7 +390,7 @@ expect_semicolon :: proc(p: ^Parser, node: ^ast.Node) -> bool { return true; } } else { - switch p.curr_tok.kind { + #partial switch p.curr_tok.kind { case .Close_Brace: case .Close_Paren: case .Else: @@ -475,7 +475,7 @@ parse_when_stmt :: proc(p: ^Parser) -> ^ast.When_Stmt { } if allow_token(p, .Else) { - switch p.curr_tok.kind { + #partial switch p.curr_tok.kind { case .When: else_stmt = parse_when_stmt(p); case .Open_Brace: @@ -550,7 +550,7 @@ parse_if_stmt :: proc(p: ^Parser) -> ^ast.If_Stmt { } if allow_token(p, .Else) { - switch p.curr_tok.kind { + #partial switch p.curr_tok.kind { case .If: else_stmt = parse_if_stmt(p); case .Open_Brace: @@ -859,7 +859,7 @@ parse_foreign_block :: proc(p: ^Parser, tok: tokenizer.Token) -> ^ast.Foreign_Bl docs := p.lead_comment; foreign_library: ^ast.Expr; - switch p.curr_tok.kind { + #partial switch p.curr_tok.kind { case .Open_Brace: i := ast.new(ast.Ident, tok.pos, end_pos(tok)); i.name = "_"; @@ -901,7 +901,7 @@ parse_foreign_decl :: proc(p: ^Parser) -> ^ast.Decl { docs := p.lead_comment; tok := expect_token(p, .Foreign); - switch p.curr_tok.kind { + #partial switch p.curr_tok.kind { case .Ident, .Open_Brace: return parse_foreign_block(p, tok); @@ -955,7 +955,7 @@ parse_foreign_decl :: proc(p: ^Parser) -> ^ast.Decl { parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { - switch p.curr_tok.kind { + #partial switch p.curr_tok.kind { // Operands case .Context, // Also allows for 'context = ' .Proc, @@ -1086,12 +1086,12 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { stmt.state_flags |= {.No_Bounds_Check}; } return stmt; - case "complete": + case "partial": stmt := parse_stmt(p); switch s in &stmt.derived { - case ast.Switch_Stmt: s.complete = true; - case ast.Type_Switch_Stmt: s.complete = true; - case: error(p, stmt.pos, "#complete can only be applied to a switch statement"); + case ast.Switch_Stmt: s.partial = true; + case ast.Type_Switch_Stmt: s.partial = true; + case: error(p, stmt.pos, "#partial can only be applied to a switch statement"); } return stmt; case "assert", "panic": @@ -1130,7 +1130,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { token_precedence :: proc(p: ^Parser, kind: tokenizer.Token_Kind) -> int { - switch kind { + #partial switch kind { case .Question: return 1; case .Ellipsis, .Range_Half: @@ -1308,7 +1308,7 @@ convert_to_ident_list :: proc(p: ^Parser, list: []Expr_And_Flags, ignore_flags, is_token_field_prefix :: proc(p: ^Parser) -> Field_Prefix { using Field_Prefix; - switch p.curr_tok.kind { + #partial switch p.curr_tok.kind { case .EOF: return Invalid; case .Using: @@ -1323,7 +1323,7 @@ is_token_field_prefix :: proc(p: ^Parser) -> Field_Prefix { case .Hash: advance_token(p); defer advance_token(p); - switch p.curr_tok.kind { + #partial switch p.curr_tok.kind { case .Ident: switch p.curr_tok.text { case "no_alias": @@ -1359,7 +1359,7 @@ parse_field_prefixes :: proc(p: ^Parser) -> ast.Field_Flags { for kind in Field_Prefix { count := counts[kind]; using Field_Prefix; - #complete switch kind { + switch kind { case Invalid, Unknown: // Ignore case Using: if count > 1 do error(p, p.curr_tok.pos, "multiple 'using' in this field list"); @@ -1391,7 +1391,7 @@ check_field_flag_prefixes :: proc(p: ^Parser, name_count: int, allowed_flags, se for flag in ast.Field_Flag { if flag notin allowed_flags && flag in flags { - #complete switch flag { + switch flag { case .Using: error(p, p.curr_tok.pos, "'using' is not allowed within this field list"); case .No_Alias: @@ -1832,7 +1832,7 @@ check_poly_params_for_type :: proc(p: ^Parser, poly_params: ^ast.Field_List, tok parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { - switch p.curr_tok.kind { + #partial switch p.curr_tok.kind { case .Ident: return parse_ident(p); @@ -1945,7 +1945,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { expr := parse_unary_expr(p, lhs); pi := ast.Proc_Inlining.None; - switch tok.kind { + #partial switch tok.kind { case .Inline: pi = ast.Proc_Inlining.Inline; case .No_Inline: @@ -2537,7 +2537,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a loop := true; is_lhs := lhs; for loop { - switch p.curr_tok.kind { + #partial switch p.curr_tok.kind { case: loop = false; @@ -2556,7 +2556,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a p.expr_level += 1; open := expect_token(p, .Open_Bracket); - switch p.curr_tok.kind { + #partial switch p.curr_tok.kind { case .Colon, .Ellipsis, .Range_Half: // NOTE(bill): Do not err yet break; @@ -2564,7 +2564,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a indicies[0] = parse_expr(p, false); } - switch p.curr_tok.kind { + #partial switch p.curr_tok.kind { case .Ellipsis, .Range_Half: error(p, p.curr_tok.pos, "expected a colon, not a range"); fallthrough; @@ -2602,7 +2602,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a case .Period: tok := expect_token(p, .Period); - switch p.curr_tok.kind { + #partial switch p.curr_tok.kind { case .Ident: field := parse_ident(p); @@ -2659,7 +2659,7 @@ parse_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { return parse_binary_expr(p, lhs, 0+1); } parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { - switch p.curr_tok.kind { + #partial switch p.curr_tok.kind { case .Transmute, .Cast: tok := advance_token(p); open := expect_token(p, .Open_Paren); @@ -2812,7 +2812,7 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt { case op.kind == .Colon: expect_token_after(p, .Colon, "identifier list"); if .Label in flags && len(lhs) == 1 { - switch p.curr_tok.kind { + #partial switch p.curr_tok.kind { case .Open_Brace, .If, .For, .Switch: label := lhs[0]; stmt := parse_stmt(p); @@ -2847,7 +2847,7 @@ parse_value_decl :: proc(p: ^Parser, names: []^ast.Expr, docs: ^ast.Comment_Grou values: []^ast.Expr; type := parse_type_or_ident(p); - switch p.curr_tok.kind { + #partial switch p.curr_tok.kind { case .Eq, .Colon: sep := advance_token(p); is_mutable = sep.kind != .Colon; @@ -2910,7 +2910,7 @@ parse_import_decl :: proc(p: ^Parser, kind := Import_Decl_Kind.Standard) -> ^ast import_name: tokenizer.Token; is_using := kind != Import_Decl_Kind.Standard; - switch p.curr_tok.kind { + #partial switch p.curr_tok.kind { case .Ident: import_name = advance_token(p); case: diff --git a/core/odin/tokenizer/token.odin b/core/odin/tokenizer/token.odin index d692da5d9..8ec873a59 100644 --- a/core/odin/tokenizer/token.odin +++ b/core/odin/tokenizer/token.odin @@ -313,7 +313,7 @@ is_literal :: proc(kind: Token_Kind) -> bool { return Token_Kind.B_Literal_Begin < kind && kind < Token_Kind.B_Literal_End; } is_operator :: proc(kind: Token_Kind) -> bool { - switch kind { + #partial switch kind { case .B_Operator_Begin .. .B_Operator_End: return true; case .In, .Notin: diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index 4bc9a2225..05d959115 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -37,7 +37,7 @@ Type_Kind :: enum { type_kind :: proc(T: typeid) -> Type_Kind { ti := type_info_of(T); if ti != nil { - #complete switch _ in ti.variant { + switch _ in ti.variant { case runtime.Type_Info_Named: return .Named; case runtime.Type_Info_Integer: return .Integer; case runtime.Type_Info_Rune: return .Rune; diff --git a/core/reflect/types.odin b/core/reflect/types.odin index ba35c9fc4..9c382a8e3 100644 --- a/core/reflect/types.odin +++ b/core/reflect/types.odin @@ -40,6 +40,14 @@ are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool { _, ok := b.variant.(rt.Type_Info_Complex); return ok; + case rt.Type_Info_Quaternion: + _, ok := b.variant.(rt.Type_Info_Quaternion); + return ok; + + case rt.Type_Info_Type_Id: + _, ok := b.variant.(rt.Type_Info_Type_Id); + return ok; + case rt.Type_Info_String: _, ok := b.variant.(rt.Type_Info_String); return ok; @@ -174,7 +182,7 @@ are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool { is_signed :: proc(info: ^rt.Type_Info) -> bool { if info == nil do return false; - switch i in rt.type_info_base(info).variant { + #partial switch i in rt.type_info_base(info).variant { case rt.Type_Info_Integer: return i.signed; case rt.Type_Info_Float: return true; } @@ -309,6 +317,7 @@ write_type :: proc(buf: ^strings.Builder, ti: ^rt.Type_Info) { write_byte(buf, info.signed ? 'i' : 'u'); write_i64(buf, i64(8*ti.size), 10); switch info.endianness { + case .Platform: // Okay case .Little: write_string(buf, "le"); case .Big: write_string(buf, "be"); } @@ -321,6 +330,9 @@ write_type :: proc(buf: ^strings.Builder, ti: ^rt.Type_Info) { case rt.Type_Info_Complex: write_string(buf, "complex"); write_i64(buf, i64(8*ti.size), 10); + case rt.Type_Info_Quaternion: + write_string(buf, "quaternion"); + write_i64(buf, i64(8*ti.size), 10); case rt.Type_Info_String: if info.is_cstring { write_string(buf, "cstring"); @@ -399,7 +411,7 @@ write_type :: proc(buf: ^strings.Builder, ti: ^rt.Type_Info) { write_type(buf, info.value); case rt.Type_Info_Struct: - #complete switch info.soa_kind { + switch info.soa_kind { case .None: // Ignore case .Fixed: write_string(buf, "#soa["); diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 340267497..f9ffbdd62 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -305,7 +305,7 @@ type_info_base :: proc "contextless" (info: ^Type_Info) -> ^Type_Info { base := info; loop: for { - switch i in base.variant { + #partial switch i in base.variant { case Type_Info_Named: base = i.base; case: break loop; } @@ -319,7 +319,7 @@ type_info_core :: proc "contextless" (info: ^Type_Info) -> ^Type_Info { base := info; loop: for { - 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_Opaque: base = i.elem; diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index d377c7bd0..3226a774b 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -110,6 +110,9 @@ print_type :: proc(fd: os.Handle, ti: ^Type_Info) { case Type_Info_Complex: os.write_string(fd, "complex"); print_u64(fd, u64(8*ti.size)); + case Type_Info_Quaternion: + os.write_string(fd, "quaternion"); + print_u64(fd, u64(8*ti.size)); case Type_Info_String: os.write_string(fd, "string"); case Type_Info_Boolean: @@ -183,7 +186,7 @@ print_type :: proc(fd: os.Handle, ti: ^Type_Info) { print_type(fd, info.value); case Type_Info_Struct: - #complete switch info.soa_kind { + switch info.soa_kind { case .None: // Ignore case .Fixed: os.write_string(fd, "#soa["); @@ -263,7 +266,7 @@ print_type :: proc(fd: os.Handle, ti: ^Type_Info) { case Type_Info_Bit_Set: os.write_string(fd, "bit_set["); - switch elem in type_info_base(info.elem).variant { + #partial switch elem in type_info_base(info.elem).variant { case Type_Info_Enum: print_type(fd, info.elem); case Type_Info_Rune: diff --git a/core/sync/atomic.odin b/core/sync/atomic.odin index 6a9a1f9a3..996c14f47 100644 --- a/core/sync/atomic.odin +++ b/core/sync/atomic.odin @@ -11,7 +11,7 @@ Ordering :: enum { } strongest_failure_ordering :: inline proc "contextless" (order: Ordering) -> Ordering { - #complete switch order { + switch order { case .Relaxed: return .Relaxed; case .Release: return .Relaxed; case .Acquire: return .Acquire; @@ -22,7 +22,7 @@ strongest_failure_ordering :: inline proc "contextless" (order: Ordering) -> Ord } fence :: inline proc "contextless" ($order: Ordering) { - #complete switch order { + switch order { case .Relaxed: panic("there is no such thing as a relaxed fence"); case .Release: intrinsics.atomic_fence_rel(); case .Acquire: intrinsics.atomic_fence_acq(); @@ -34,7 +34,7 @@ fence :: inline proc "contextless" ($order: Ordering) { atomic_store :: inline proc "contextless" (dst: ^$T, val: T, $order: Ordering) { - #complete switch order { + switch order { case .Relaxed: intrinsics.atomic_store_relaxed(dst, val); case .Release: intrinsics.atomic_store_rel(dst, val); case .Sequentially_Consistent: intrinsics.atomic_store(dst, val); @@ -45,7 +45,7 @@ atomic_store :: inline proc "contextless" (dst: ^$T, val: T, $order: Ordering) { } atomic_load :: inline proc "contextless" (dst: ^$T, $order: Ordering) -> T { - #complete switch order { + switch order { case .Relaxed: return intrinsics.atomic_load_relaxed(dst); case .Acquire: return intrinsics.atomic_load_acq(dst); case .Sequentially_Consistent: return intrinsics.atomic_load(dst); @@ -57,7 +57,7 @@ atomic_load :: inline proc "contextless" (dst: ^$T, $order: Ordering) -> T { } atomic_swap :: inline proc "contextless" (dst: ^$T, val: T, $order: Ordering) -> T { - #complete switch order { + switch order { case .Relaxed: return intrinsics.atomic_xchg_relaxed(dst, val); case .Release: return intrinsics.atomic_xchg_rel(dst, val); case .Acquire: return intrinsics.atomic_xchg_acq(dst, val); @@ -138,7 +138,7 @@ atomic_compare_exchange_weak :: inline proc "contextless" (dst: ^$T, old, new: T atomic_add :: inline proc "contextless" (dst: ^$T, val: T, $order: Ordering) -> T { - #complete switch order { + switch order { case .Relaxed: return intrinsics.atomic_add_relaxed(dst, val); case .Release: return intrinsics.atomic_add_rel(dst, val); case .Acquire: return intrinsics.atomic_add_acq(dst, val); @@ -150,7 +150,7 @@ atomic_add :: inline proc "contextless" (dst: ^$T, val: T, $order: Ordering) -> } atomic_sub :: inline proc "contextless" (dst: ^$T, val: T, $order: Ordering) -> T { - #complete switch order { + switch order { case .Relaxed: return intrinsics.atomic_sub_relaxed(dst, val); case .Release: return intrinsics.atomic_sub_rel(dst, val); case .Acquire: return intrinsics.atomic_sub_acq(dst, val); @@ -162,7 +162,7 @@ atomic_sub :: inline proc "contextless" (dst: ^$T, val: T, $order: Ordering) -> } atomic_and :: inline proc "contextless" (dst: ^$T, val: T, $order: Ordering) -> T { - #complete switch order { + switch order { case .Relaxed: return intrinsics.atomic_and_relaxed(dst, val); case .Release: return intrinsics.atomic_and_rel(dst, val); case .Acquire: return intrinsics.atomic_and_acq(dst, val); @@ -174,7 +174,7 @@ atomic_and :: inline proc "contextless" (dst: ^$T, val: T, $order: Ordering) -> } atomic_nand :: inline proc "contextless" (dst: ^$T, val: T, $order: Ordering) -> T { - #complete switch order { + switch order { case .Relaxed: return intrinsics.atomic_nand_relaxed(dst, val); case .Release: return intrinsics.atomic_nand_rel(dst, val); case .Acquire: return intrinsics.atomic_nand_acq(dst, val); @@ -186,7 +186,7 @@ atomic_nand :: inline proc "contextless" (dst: ^$T, val: T, $order: Ordering) -> } atomic_or :: inline proc "contextless" (dst: ^$T, val: T, $order: Ordering) -> T { - #complete switch order { + switch order { case .Relaxed: return intrinsics.atomic_or_relaxed(dst, val); case .Release: return intrinsics.atomic_or_rel(dst, val); case .Acquire: return intrinsics.atomic_or_acq(dst, val); @@ -198,7 +198,7 @@ atomic_or :: inline proc "contextless" (dst: ^$T, val: T, $order: Ordering) -> T } atomic_xor :: inline proc "contextless" (dst: ^$T, val: T, $order: Ordering) -> T { - #complete switch order { + switch order { case .Relaxed: return intrinsics.atomic_xor_relaxed(dst, val); case .Release: return intrinsics.atomic_xor_rel(dst, val); case .Acquire: return intrinsics.atomic_xor_acq(dst, val); diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index af9e606cb..062ea73b9 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -7,6 +7,7 @@ import "core:thread" import "core:reflect" import "intrinsics" + /* The Odin programming language is fast, concise, readable, pragmatic and open sourced. It is designed with the intent of replacing C with the following goals: @@ -1233,8 +1234,8 @@ implicit_selector_expression :: proc() { } -complete_switch :: proc() { - fmt.println("\n# complete_switch"); +partial_switch :: proc() { + fmt.println("\n# partial_switch"); { // enum Foo :: enum { A, @@ -1244,22 +1245,31 @@ complete_switch :: proc() { }; f := Foo.A; - #complete switch f { + switch f { case .A: fmt.println("A"); case .B: fmt.println("B"); case .C: fmt.println("C"); case .D: fmt.println("D"); case: fmt.println("?"); } + + #partial switch f { + case .A: fmt.println("A"); + case .D: fmt.println("D"); + } } { // union Foo :: union {int, bool}; f: Foo = 123; - #complete switch in f { + switch in f { case int: fmt.println("int"); case bool: fmt.println("bool"); case: } + + #partial switch in f { + case bool: fmt.println("bool"); + } } } @@ -1820,7 +1830,7 @@ main :: proc() { array_programming(); map_type(); implicit_selector_expression(); - complete_switch(); + partial_switch(); cstring_example(); bit_set_type(); deferred_procedure_associations(); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 7d5648018..7bb6924b4 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -807,12 +807,11 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { } } - bool complete = ss->complete; + bool is_partial = ss->partial; - if (complete) { + if (is_partial) { if (!is_type_enum(x.type)) { - error(x.expr, "#complete switch statement can be only used with an enum type"); - complete = false; + error(x.expr, "#partial switch statement can be only used with an enum type"); } } @@ -877,9 +876,6 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { Operand a1 = lhs; Operand b1 = rhs; check_comparison(ctx, &a1, &b1, Token_LtEq); - if (complete) { - error(lhs.expr, "#complete switch statement does not allow ranges"); - } add_constant_switch_case(ctx, &seen, lhs); if (upper_op == Token_GtEq) { @@ -926,9 +922,6 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { continue; } if (y.mode != Addressing_Constant) { - if (complete) { - error(y.expr, "#complete switch statement only allows constant case clauses"); - } continue; } @@ -942,7 +935,7 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { check_close_scope(ctx); } - if (complete) { + if (!is_partial && is_type_enum(x.type)) { Type *et = base_type(x.type); GB_ASSERT(is_type_enum(et)); auto fields = et->Enum.fields; @@ -968,18 +961,17 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { defer (begin_error_block()); if (unhandled.count == 1) { - error_no_newline(node, "Unhandled switch case: "); + error_no_newline(node, "Unhandled switch case: %.*s", LIT(unhandled[0]->token.string)); } else { error_no_newline(node, "Unhandled switch cases: "); - } - for_array(i, unhandled) { - Entity *f = unhandled[i]; - if (i > 0) { - error_line(", "); + for_array(i, unhandled) { + Entity *f = unhandled[i]; + error_line("\t%.*s\n", LIT(f->token.string)); } - error_line("%.*s", LIT(f->token.string)); } error_line("\n"); + + error_line("\tSuggestion: Was '#partial switch' wanted? This replaces the previous '#complete switch'.\n"); } } } @@ -1042,11 +1034,10 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { return; } - bool complete = ss->complete; - if (complete) { + bool is_partial = ss->partial; + if (is_partial) { if (switch_kind != TypeSwitch_Union) { - error(node, "#complete switch statement may only be used with a union"); - complete = false; + error(node, "#partial switch statement may only be used with a union"); } } @@ -1174,7 +1165,7 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { check_close_scope(ctx); } - if (complete) { + if (!is_partial && is_type_union(type_deref(x.type))) { Type *ut = base_type(type_deref(x.type)); GB_ASSERT(is_type_union(ut)); auto variants = ut->Union.variants; @@ -1191,20 +1182,20 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { if (unhandled.count > 0) { if (unhandled.count == 1) { - error_no_newline(node, "Unhandled switch case: "); - } else { - error_no_newline(node, "Unhandled switch cases: "); - } - for_array(i, unhandled) { - Type *t = unhandled[i]; - if (i > 0) { - error_line(", "); - } - gbString s = type_to_string(t); - error_line("%s", s); + gbString s = type_to_string(unhandled[0]); + error_no_newline(node, "Unhandled switch case: %s", s); gb_string_free(s); + } else { + error_no_newline(node, "Unhandled switch cases:\n"); + for_array(i, unhandled) { + Type *t = unhandled[i]; + gbString s = type_to_string(t); + error_line("\t%s\n", s); + gb_string_free(s); + } } error_line("\n"); + error_line("\tSuggestion: Was '#partial switch' wanted? This replaces the previous '#complete switch'.\n"); } } } diff --git a/src/parser.cpp b/src/parser.cpp index fbbb9e1cb..0e9b20e52 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -766,6 +766,7 @@ Ast *ast_switch_stmt(AstFile *f, Token token, Ast *init, Ast *tag, Ast *body) { result->SwitchStmt.init = init; result->SwitchStmt.tag = tag; result->SwitchStmt.body = body; + result->SwitchStmt.partial = false; return result; } @@ -775,6 +776,7 @@ Ast *ast_type_switch_stmt(AstFile *f, Token token, Ast *tag, Ast *body) { result->TypeSwitchStmt.token = token; result->TypeSwitchStmt.tag = tag; result->TypeSwitchStmt.body = body; + result->TypeSwitchStmt.partial = false; return result; } @@ -4060,16 +4062,32 @@ Ast *parse_stmt(AstFile *f) { s = parse_stmt(f); switch (s->kind) { case Ast_SwitchStmt: - s->SwitchStmt.complete = true; + s->SwitchStmt.partial = false; + syntax_warning(token, "#complete is now the default and has been replaced with its opposite: #partial"); break; case Ast_TypeSwitchStmt: - s->TypeSwitchStmt.complete = true; + s->TypeSwitchStmt.partial = false; + syntax_warning(token, "#complete is now the default and has been replaced with its opposite: #partial"); break; default: syntax_error(token, "#complete can only be applied to a switch statement"); break; } return s; + } else if (tag == "partial") { + s = parse_stmt(f); + switch (s->kind) { + case Ast_SwitchStmt: + s->SwitchStmt.partial = true; + break; + case Ast_TypeSwitchStmt: + s->TypeSwitchStmt.partial = true; + break; + default: + syntax_error(token, "#partial can only be applied to a switch statement"); + break; + } + return s; } else if (tag == "assert") { Ast *t = ast_basic_directive(f, hash_token, tag); return ast_expr_stmt(f, parse_call_expr(f, t)); diff --git a/src/parser.hpp b/src/parser.hpp index 7101e0247..983db1042 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -363,20 +363,20 @@ AST_KIND(_ComplexStmtBegin, "", bool) \ Entity *implicit_entity; \ }) \ AST_KIND(SwitchStmt, "switch statement", struct { \ - Token token; \ - Ast *label; \ - Ast *init; \ - Ast *tag; \ - Ast *body; \ - bool complete; \ + Token token; \ + Ast *label; \ + Ast *init; \ + Ast *tag; \ + Ast *body; \ + bool partial; \ }) \ AST_KIND(TypeSwitchStmt, "type switch statement", struct { \ - Token token; \ - Ast *label; \ - Ast *tag; \ - Ast *body; \ - bool complete; \ - }) \ + Token token; \ + Ast *label; \ + Ast *tag; \ + Ast *body; \ + bool partial; \ +}) \ AST_KIND(DeferStmt, "defer statement", struct { Token token; Ast *stmt; }) \ AST_KIND(BranchStmt, "branch statement", struct { Token token; Ast *label; }) \ AST_KIND(UsingStmt, "using statement", struct { \