mirror of
https://github.com/odin-lang/Odin.git
synced 2026-02-15 23:54:07 +00:00
Implement #complete switch by default, replace with #partial switch #511
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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] == '-' {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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[");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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 { \
|
||||
|
||||
Reference in New Issue
Block a user