mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 15:18:49 +00:00
Implement #complete switch by default, replace with #partial switch #511
This commit is contained in:
+105
-105
@@ -106,11 +106,11 @@ create_from_tokenizer :: proc(t: ^Tokenizer) -> (^Parser, bool) {
|
|||||||
p := new(Parser);
|
p := new(Parser);
|
||||||
for {
|
for {
|
||||||
tok := scan(t);
|
tok := scan(t);
|
||||||
if tok.kind == Kind.Illegal {
|
if tok.kind == .Illegal {
|
||||||
return p, false;
|
return p, false;
|
||||||
}
|
}
|
||||||
append(&p.tokens, tok);
|
append(&p.tokens, tok);
|
||||||
if tok.kind == Kind.EOF {
|
if tok.kind == .EOF {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,7 +120,7 @@ create_from_tokenizer :: proc(t: ^Tokenizer) -> (^Parser, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(p.tokens) == 0 {
|
if len(p.tokens) == 0 {
|
||||||
tok := Token{kind = Kind.EOF};
|
tok := Token{kind = .EOF};
|
||||||
tok.line, tok.column = 1, 1;
|
tok.line, tok.column = 1, 1;
|
||||||
append(&p.tokens, tok);
|
append(&p.tokens, tok);
|
||||||
return p, true;
|
return p, true;
|
||||||
@@ -134,8 +134,8 @@ create_from_tokenizer :: proc(t: ^Tokenizer) -> (^Parser, bool) {
|
|||||||
p.dict_stack = make([dynamic]^Dict, 0, 4);
|
p.dict_stack = make([dynamic]^Dict, 0, 4);
|
||||||
append(&p.dict_stack, &p.root);
|
append(&p.dict_stack, &p.root);
|
||||||
|
|
||||||
for p.curr_token.kind != Kind.EOF &&
|
for p.curr_token.kind != .EOF &&
|
||||||
p.curr_token.kind != Kind.Illegal &&
|
p.curr_token.kind != .Illegal &&
|
||||||
p.curr_token_index < len(p.tokens) {
|
p.curr_token_index < len(p.tokens) {
|
||||||
if !parse_assignment(p) {
|
if !parse_assignment(p) {
|
||||||
break;
|
break;
|
||||||
@@ -147,7 +147,7 @@ create_from_tokenizer :: proc(t: ^Tokenizer) -> (^Parser, bool) {
|
|||||||
|
|
||||||
destroy :: proc(p: ^Parser) {
|
destroy :: proc(p: ^Parser) {
|
||||||
destroy_value :: proc(value: Value) {
|
destroy_value :: proc(value: Value) {
|
||||||
switch v in value {
|
#partial switch v in value {
|
||||||
case Array:
|
case Array:
|
||||||
for elem in v do destroy_value(elem);
|
for elem in v do destroy_value(elem);
|
||||||
delete(v);
|
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) {
|
unquote_string :: proc(p: ^Parser, t: Token) -> (string, bool) {
|
||||||
if t.kind != Kind.String {
|
if t.kind != .String {
|
||||||
return t.lit, true;
|
return t.lit, true;
|
||||||
}
|
}
|
||||||
s := t.lit;
|
s := t.lit;
|
||||||
@@ -368,8 +368,8 @@ expect_operator :: proc(p: ^Parser) -> Token {
|
|||||||
|
|
||||||
fix_advance :: proc(p: ^Parser) {
|
fix_advance :: proc(p: ^Parser) {
|
||||||
for {
|
for {
|
||||||
switch t := p.curr_token; t.kind {
|
#partial switch t := p.curr_token; t.kind {
|
||||||
case Kind.EOF, Kind.Semicolon:
|
case .EOF, .Semicolon:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
next_token(p);
|
next_token(p);
|
||||||
@@ -377,7 +377,7 @@ fix_advance :: proc(p: ^Parser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
copy_value :: proc(value: Value) -> Value {
|
copy_value :: proc(value: Value) -> Value {
|
||||||
switch v in value {
|
#partial switch v in value {
|
||||||
case Array:
|
case Array:
|
||||||
a := make(Array, len(v));
|
a := make(Array, len(v));
|
||||||
for elem, idx in 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) {
|
parse_operand :: proc(p: ^Parser) -> (Value, Pos) {
|
||||||
tok := p.curr_token;
|
tok := p.curr_token;
|
||||||
switch p.curr_token.kind {
|
#partial switch p.curr_token.kind {
|
||||||
case Kind.Ident:
|
case .Ident:
|
||||||
next_token(p);
|
next_token(p);
|
||||||
v, ok := lookup_value(p, tok.lit);
|
v, ok := lookup_value(p, tok.lit);
|
||||||
if !ok do error(p, tok.pos, "Undeclared identifier %s", tok.lit);
|
if !ok do error(p, tok.pos, "Undeclared identifier %s", tok.lit);
|
||||||
return v, tok.pos;
|
return v, tok.pos;
|
||||||
|
|
||||||
case Kind.True:
|
case .True:
|
||||||
next_token(p);
|
next_token(p);
|
||||||
return true, tok.pos;
|
return true, tok.pos;
|
||||||
case Kind.False:
|
case .False:
|
||||||
next_token(p);
|
next_token(p);
|
||||||
return false, tok.pos;
|
return false, tok.pos;
|
||||||
|
|
||||||
case Kind.Nil:
|
case .Nil:
|
||||||
next_token(p);
|
next_token(p);
|
||||||
return Nil_Value{}, tok.pos;
|
return Nil_Value{}, tok.pos;
|
||||||
|
|
||||||
case Kind.Integer:
|
case .Integer:
|
||||||
next_token(p);
|
next_token(p);
|
||||||
return strconv.parse_i64(tok.lit), tok.pos;
|
return strconv.parse_i64(tok.lit), tok.pos;
|
||||||
|
|
||||||
case Kind.Float:
|
case .Float:
|
||||||
next_token(p);
|
next_token(p);
|
||||||
return strconv.parse_f64(tok.lit), tok.pos;
|
return strconv.parse_f64(tok.lit), tok.pos;
|
||||||
|
|
||||||
case Kind.String:
|
case .String:
|
||||||
next_token(p);
|
next_token(p);
|
||||||
str, ok := unquote_string(p, tok);
|
str, ok := unquote_string(p, tok);
|
||||||
if !ok do error(p, tok.pos, "Unable to unquote string");
|
if !ok do error(p, tok.pos, "Unable to unquote string");
|
||||||
return string(str), tok.pos;
|
return string(str), tok.pos;
|
||||||
|
|
||||||
case Kind.Open_Paren:
|
case .Open_Paren:
|
||||||
expect_token(p, Kind.Open_Paren);
|
expect_token(p, .Open_Paren);
|
||||||
expr, _ := parse_expr(p);
|
expr, _ := parse_expr(p);
|
||||||
expect_token(p, Kind.Close_Paren);
|
expect_token(p, .Close_Paren);
|
||||||
return expr, tok.pos;
|
return expr, tok.pos;
|
||||||
|
|
||||||
case Kind.Open_Bracket:
|
case .Open_Bracket:
|
||||||
expect_token(p, Kind.Open_Bracket);
|
expect_token(p, .Open_Bracket);
|
||||||
elems := make([dynamic]Value, 0, 4);
|
elems := make([dynamic]Value, 0, 4);
|
||||||
for p.curr_token.kind != Kind.Close_Bracket &&
|
for p.curr_token.kind != .Close_Bracket &&
|
||||||
p.curr_token.kind != Kind.EOF {
|
p.curr_token.kind != .EOF {
|
||||||
elem, _ := parse_expr(p);
|
elem, _ := parse_expr(p);
|
||||||
append(&elems, elem);
|
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);
|
next_token(p);
|
||||||
} else if !allow_token(p, Kind.Comma) {
|
} else if !allow_token(p, .Comma) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
expect_token(p, Kind.Close_Bracket);
|
expect_token(p, .Close_Bracket);
|
||||||
return Array(elems[:]), tok.pos;
|
return Array(elems[:]), tok.pos;
|
||||||
|
|
||||||
case Kind.Open_Brace:
|
case .Open_Brace:
|
||||||
expect_token(p, Kind.Open_Brace);
|
expect_token(p, .Open_Brace);
|
||||||
|
|
||||||
dict := Dict{};
|
dict := Dict{};
|
||||||
append(&p.dict_stack, &dict);
|
append(&p.dict_stack, &dict);
|
||||||
defer pop(&p.dict_stack);
|
defer pop(&p.dict_stack);
|
||||||
|
|
||||||
for p.curr_token.kind != Kind.Close_Brace &&
|
for p.curr_token.kind != .Close_Brace &&
|
||||||
p.curr_token.kind != Kind.EOF {
|
p.curr_token.kind != .EOF {
|
||||||
name_tok := p.curr_token;
|
name_tok := p.curr_token;
|
||||||
if !allow_token(p, Kind.Ident) && !allow_token(p, Kind.String) {
|
if !allow_token(p, .Ident) && !allow_token(p, .String) {
|
||||||
name_tok = expect_token(p, Kind.Ident);
|
name_tok = expect_token(p, .Ident);
|
||||||
}
|
}
|
||||||
|
|
||||||
name, ok := unquote_string(p, name_tok);
|
name, ok := unquote_string(p, name_tok);
|
||||||
if !ok do error(p, tok.pos, "Unable to unquote string");
|
if !ok do error(p, tok.pos, "Unable to unquote string");
|
||||||
expect_token(p, Kind.Assign);
|
expect_token(p, .Assign);
|
||||||
elem, _ := parse_expr(p);
|
elem, _ := parse_expr(p);
|
||||||
|
|
||||||
if _, ok2 := dict[name]; ok2 {
|
if _, ok2 := dict[name]; ok2 {
|
||||||
@@ -488,13 +488,13 @@ parse_operand :: proc(p: ^Parser) -> (Value, Pos) {
|
|||||||
dict[name] = elem;
|
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);
|
next_token(p);
|
||||||
} else if !allow_token(p, Kind.Comma) {
|
} else if !allow_token(p, .Comma) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect_token(p, Kind.Close_Brace);
|
expect_token(p, .Close_Brace);
|
||||||
return dict, tok.pos;
|
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) {
|
parse_atom_expr :: proc(p: ^Parser, operand: Value, pos: Pos) -> (Value, Pos) {
|
||||||
loop := true;
|
loop := true;
|
||||||
for operand := operand; loop; {
|
for operand := operand; loop; {
|
||||||
switch p.curr_token.kind {
|
#partial switch p.curr_token.kind {
|
||||||
case Kind.Period:
|
case .Period:
|
||||||
next_token(p);
|
next_token(p);
|
||||||
tok := next_token(p);
|
tok := next_token(p);
|
||||||
|
|
||||||
switch tok.kind {
|
#partial switch tok.kind {
|
||||||
case Kind.Ident:
|
case .Ident:
|
||||||
d, ok := operand.(Dict);
|
d, ok := operand.(Dict);
|
||||||
if !ok || d == nil {
|
if !ok || d == nil {
|
||||||
error(p, tok.pos, "Expected a dictionary");
|
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;
|
operand = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Kind.Open_Bracket:
|
case .Open_Bracket:
|
||||||
expect_token(p, Kind.Open_Bracket);
|
expect_token(p, .Open_Bracket);
|
||||||
index, index_pos := parse_expr(p);
|
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:
|
case Array:
|
||||||
i, ok := index.(i64);
|
i, ok := index.(i64);
|
||||||
if !ok {
|
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) {
|
parse_unary_expr :: proc(p: ^Parser) -> (Value, Pos) {
|
||||||
op := p.curr_token;
|
op := p.curr_token;
|
||||||
switch p.curr_token.kind {
|
#partial switch p.curr_token.kind {
|
||||||
case Kind.At:
|
case .At:
|
||||||
next_token(p);
|
next_token(p);
|
||||||
tok := expect_token(p, Kind.String);
|
tok := expect_token(p, .String);
|
||||||
v, ok := lookup_value(p, tok.lit);
|
v, ok := lookup_value(p, tok.lit);
|
||||||
if !ok do error(p, tok.pos, "Undeclared identifier %s", tok.lit);
|
if !ok do error(p, tok.pos, "Undeclared identifier %s", tok.lit);
|
||||||
return parse_atom_expr(p, v, tok.pos);
|
return parse_atom_expr(p, v, tok.pos);
|
||||||
|
|
||||||
case Kind.Add, Kind.Sub:
|
case .Add, .Sub:
|
||||||
next_token(p);
|
next_token(p);
|
||||||
// TODO(bill): Calcuate values as you go!
|
// TODO(bill): Calcuate values as you go!
|
||||||
expr, pos := parse_unary_expr(p);
|
expr, pos := parse_unary_expr(p);
|
||||||
|
|
||||||
switch e in expr {
|
#partial switch e in expr {
|
||||||
case i64: if op.kind == Kind.Sub do return -e, pos;
|
case i64: if op.kind == .Sub do return -e, pos;
|
||||||
case f64: if op.kind == Kind.Sub do return -e, pos;
|
case f64: if op.kind == .Sub do return -e, pos;
|
||||||
case:
|
case:
|
||||||
error(p, op.pos, "Unary operator %s can only be used on integers or floats", op.lit);
|
error(p, op.pos, "Unary operator %s can only be used on integers or floats", op.lit);
|
||||||
return nil, op.pos;
|
return nil, op.pos;
|
||||||
@@ -610,7 +610,7 @@ parse_unary_expr :: proc(p: ^Parser) -> (Value, Pos) {
|
|||||||
|
|
||||||
return expr, op.pos;
|
return expr, op.pos;
|
||||||
|
|
||||||
case Kind.Not:
|
case .Not:
|
||||||
next_token(p);
|
next_token(p);
|
||||||
expr, _ := parse_unary_expr(p);
|
expr, _ := parse_unary_expr(p);
|
||||||
if v, ok := expr.(bool); ok {
|
if v, ok := expr.(bool); ok {
|
||||||
@@ -625,7 +625,7 @@ parse_unary_expr :: proc(p: ^Parser) -> (Value, Pos) {
|
|||||||
|
|
||||||
|
|
||||||
value_order :: proc(v: Value) -> int {
|
value_order :: proc(v: Value) -> int {
|
||||||
switch _ in v {
|
#partial switch _ in v {
|
||||||
case bool, string:
|
case bool, string:
|
||||||
return 1;
|
return 1;
|
||||||
case i64:
|
case i64:
|
||||||
@@ -641,13 +641,13 @@ match_values :: proc(left, right: ^Value) -> bool {
|
|||||||
return match_values(right, left);
|
return match_values(right, left);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch x in left^ {
|
#partial switch x in left^ {
|
||||||
case:
|
case:
|
||||||
right^ = left^;
|
right^ = left^;
|
||||||
case bool, string:
|
case bool, string:
|
||||||
return true;
|
return true;
|
||||||
case i64:
|
case i64:
|
||||||
switch y in right^ {
|
#partial switch y in right^ {
|
||||||
case i64:
|
case i64:
|
||||||
return true;
|
return true;
|
||||||
case f64:
|
case f64:
|
||||||
@@ -656,7 +656,7 @@ match_values :: proc(left, right: ^Value) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case f64:
|
case f64:
|
||||||
switch y in right {
|
#partial switch y in right {
|
||||||
case f64:
|
case f64:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -671,59 +671,59 @@ calculate_binary_value :: proc(p: ^Parser, op: Kind, a, b: Value) -> (Value, boo
|
|||||||
match_values(&x, &y);
|
match_values(&x, &y);
|
||||||
|
|
||||||
|
|
||||||
switch a in x {
|
#partial switch a in x {
|
||||||
case: return x, true;
|
case: return x, true;
|
||||||
|
|
||||||
case bool:
|
case bool:
|
||||||
b, ok := y.(bool);
|
b, ok := y.(bool);
|
||||||
if !ok do return nil, false;
|
if !ok do return nil, false;
|
||||||
switch op {
|
#partial switch op {
|
||||||
case Kind.Eq: return a == b, true;
|
case .Eq: return a == b, true;
|
||||||
case Kind.NotEq: return a != b, true;
|
case .NotEq: return a != b, true;
|
||||||
case Kind.And: return a && b, true;
|
case .And: return a && b, true;
|
||||||
case Kind.Or: return a || b, true;
|
case .Or: return a || b, true;
|
||||||
}
|
}
|
||||||
|
|
||||||
case i64:
|
case i64:
|
||||||
b, ok := y.(i64);
|
b, ok := y.(i64);
|
||||||
if !ok do return nil, false;
|
if !ok do return nil, false;
|
||||||
switch op {
|
#partial switch op {
|
||||||
case Kind.Add: return a + b, true;
|
case .Add: return a + b, true;
|
||||||
case Kind.Sub: return a - b, true;
|
case .Sub: return a - b, true;
|
||||||
case Kind.Mul: return a * b, true;
|
case .Mul: return a * b, true;
|
||||||
case Kind.Quo: return a / b, true;
|
case .Quo: return a / b, true;
|
||||||
case Kind.Rem: return a % b, true;
|
case .Rem: return a % b, true;
|
||||||
case Kind.Eq: return a == b, true;
|
case .Eq: return a == b, true;
|
||||||
case Kind.NotEq: return a != b, true;
|
case .NotEq: return a != b, true;
|
||||||
case Kind.Lt: return a < b, true;
|
case .Lt: return a < b, true;
|
||||||
case Kind.Gt: return a > b, true;
|
case .Gt: return a > b, true;
|
||||||
case Kind.LtEq: return a <= b, true;
|
case .LtEq: return a <= b, true;
|
||||||
case Kind.GtEq: return a >= b, true;
|
case .GtEq: return a >= b, true;
|
||||||
}
|
}
|
||||||
|
|
||||||
case f64:
|
case f64:
|
||||||
b, ok := y.(f64);
|
b, ok := y.(f64);
|
||||||
if !ok do return nil, false;
|
if !ok do return nil, false;
|
||||||
|
|
||||||
switch op {
|
#partial switch op {
|
||||||
case Kind.Add: return a + b, true;
|
case .Add: return a + b, true;
|
||||||
case Kind.Sub: return a - b, true;
|
case .Sub: return a - b, true;
|
||||||
case Kind.Mul: return a * b, true;
|
case .Mul: return a * b, true;
|
||||||
case Kind.Quo: return a / b, true;
|
case .Quo: return a / b, true;
|
||||||
case Kind.Eq: return a == b, true;
|
case .Eq: return a == b, true;
|
||||||
case Kind.NotEq: return a != b, true;
|
case .NotEq: return a != b, true;
|
||||||
case Kind.Lt: return a < b, true;
|
case .Lt: return a < b, true;
|
||||||
case Kind.Gt: return a > b, true;
|
case .Gt: return a > b, true;
|
||||||
case Kind.LtEq: return a <= b, true;
|
case .LtEq: return a <= b, true;
|
||||||
case Kind.GtEq: return a >= b, true;
|
case .GtEq: return a >= b, true;
|
||||||
}
|
}
|
||||||
|
|
||||||
case string:
|
case string:
|
||||||
b, ok := y.(string);
|
b, ok := y.(string);
|
||||||
if !ok do return nil, false;
|
if !ok do return nil, false;
|
||||||
|
|
||||||
switch op {
|
#partial switch op {
|
||||||
case Kind.Add:
|
case .Add:
|
||||||
n := len(a) + len(b);
|
n := len(a) + len(b);
|
||||||
data := make([]byte, n);
|
data := make([]byte, n);
|
||||||
copy(data[:], a);
|
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);
|
append(&p.allocated_strings, s);
|
||||||
return s, true;
|
return s, true;
|
||||||
|
|
||||||
case Kind.Eq: return a == b, true;
|
case .Eq: return a == b, true;
|
||||||
case Kind.NotEq: return a != b, true;
|
case .NotEq: return a != b, true;
|
||||||
case Kind.Lt: return a < b, true;
|
case .Lt: return a < b, true;
|
||||||
case Kind.Gt: return a > b, true;
|
case .Gt: return a > b, true;
|
||||||
case Kind.LtEq: return a <= b, true;
|
case .LtEq: return a <= b, true;
|
||||||
case Kind.GtEq: 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);
|
expect_operator(p);
|
||||||
|
|
||||||
if op.kind == Kind.Question {
|
if op.kind == .Question {
|
||||||
cond := expr;
|
cond := expr;
|
||||||
x, _ := parse_expr(p);
|
x, _ := parse_expr(p);
|
||||||
expect_token(p, Kind.Colon);
|
expect_token(p, .Colon);
|
||||||
y, _ := parse_expr(p);
|
y, _ := parse_expr(p);
|
||||||
|
|
||||||
if t, ok := cond.(bool); ok {
|
if t, ok := cond.(bool); ok {
|
||||||
@@ -791,13 +791,13 @@ parse_expr :: proc(p: ^Parser) -> (Value, Pos) {
|
|||||||
expect_semicolon :: proc(p: ^Parser) {
|
expect_semicolon :: proc(p: ^Parser) {
|
||||||
kind := p.curr_token.kind;
|
kind := p.curr_token.kind;
|
||||||
|
|
||||||
switch kind {
|
#partial switch kind {
|
||||||
case Kind.Comma:
|
case .Comma:
|
||||||
error(p, p.curr_token.pos, "Expected ';', got ','");
|
error(p, p.curr_token.pos, "Expected ';', got ','");
|
||||||
next_token(p);
|
next_token(p);
|
||||||
case Kind.Semicolon:
|
case .Semicolon:
|
||||||
next_token(p);
|
next_token(p);
|
||||||
case Kind.EOF:
|
case .EOF:
|
||||||
// okay
|
// okay
|
||||||
case:
|
case:
|
||||||
error(p, p.curr_token.pos, "Expected ';', got %s", p.curr_token.lit);
|
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];
|
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);
|
next_token(p);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if p.curr_token.kind == Kind.EOF {
|
if p.curr_token.kind == .EOF {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
tok := p.curr_token;
|
tok := p.curr_token;
|
||||||
if allow_token(p, Kind.Ident) || allow_token(p, Kind.String) {
|
if allow_token(p, .Ident) || allow_token(p, .String) {
|
||||||
expect_token(p, Kind.Assign);
|
expect_token(p, .Assign);
|
||||||
name, ok := unquote_string(p, tok);
|
name, ok := unquote_string(p, tok);
|
||||||
if !ok do error(p, tok.pos, "Unable to unquote string");
|
if !ok do error(p, tok.pos, "Unable to unquote string");
|
||||||
expr, _ := parse_expr(p);
|
expr, _ := parse_expr(p);
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ kind_to_string := [len(Kind)]string{
|
|||||||
};
|
};
|
||||||
|
|
||||||
precedence :: proc(op: Kind) -> int {
|
precedence :: proc(op: Kind) -> int {
|
||||||
switch op {
|
#partial switch op {
|
||||||
case Question:
|
case Question:
|
||||||
return 1;
|
return 1;
|
||||||
case Or:
|
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));
|
ti := type_info_base(type_info_of(v.id));
|
||||||
a := any{v.data, ti.id};
|
a := any{v.data, ti.id};
|
||||||
|
|
||||||
switch info in ti.variant {
|
#partial switch info in ti.variant {
|
||||||
case Type_Info_Named:
|
case Type_Info_Named:
|
||||||
panic("Unreachable");
|
panic("Unreachable");
|
||||||
|
|
||||||
@@ -282,7 +282,7 @@ marshal_arg :: proc(b: ^strings.Builder, v: any) -> Marshal_Error {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
t := runtime.type_info_base(ti);
|
t := runtime.type_info_base(ti);
|
||||||
switch info in t.variant {
|
#partial switch info in t.variant {
|
||||||
case runtime.Type_Info_Integer:
|
case runtime.Type_Info_Integer:
|
||||||
switch info.endianness {
|
switch info.endianness {
|
||||||
case .Platform: return false;
|
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);
|
defer value.end = token_end_pos(p.prev_token);
|
||||||
|
|
||||||
token := p.curr_token;
|
token := p.curr_token;
|
||||||
switch token.kind {
|
#partial switch token.kind {
|
||||||
case Kind.Null:
|
case Kind.Null:
|
||||||
value.value = Null{};
|
value.value = Null{};
|
||||||
advance_token(p);
|
advance_token(p);
|
||||||
@@ -105,7 +105,7 @@ parse_value :: proc(p: ^Parser) -> (value: Value, err: Error) {
|
|||||||
|
|
||||||
case:
|
case:
|
||||||
if p.spec == Specification.JSON5 {
|
if p.spec == Specification.JSON5 {
|
||||||
switch token.kind {
|
#partial switch token.kind {
|
||||||
case Kind.Infinity:
|
case Kind.Infinity:
|
||||||
inf: u64 = 0x7ff0000000000000;
|
inf: u64 = 0x7ff0000000000000;
|
||||||
if token.text[0] == '-' {
|
if token.text[0] == '-' {
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ Error :: enum {
|
|||||||
|
|
||||||
|
|
||||||
destroy_value :: proc(value: Value) {
|
destroy_value :: proc(value: Value) {
|
||||||
switch v in value.value {
|
#partial switch v in value.value {
|
||||||
case Object:
|
case Object:
|
||||||
for key, elem in v {
|
for key, elem in v {
|
||||||
delete(key);
|
delete(key);
|
||||||
|
|||||||
@@ -91,28 +91,27 @@ validate_array :: proc(p: ^Parser) -> bool {
|
|||||||
validate_value :: proc(p: ^Parser) -> bool {
|
validate_value :: proc(p: ^Parser) -> bool {
|
||||||
token := p.curr_token;
|
token := p.curr_token;
|
||||||
|
|
||||||
using Kind;
|
#partial switch token.kind {
|
||||||
switch token.kind {
|
case .Null, .False, .True:
|
||||||
case Null, False, True:
|
|
||||||
advance_token(p);
|
advance_token(p);
|
||||||
return true;
|
return true;
|
||||||
case Integer, Float:
|
case .Integer, .Float:
|
||||||
advance_token(p);
|
advance_token(p);
|
||||||
return true;
|
return true;
|
||||||
case String:
|
case .String:
|
||||||
advance_token(p);
|
advance_token(p);
|
||||||
return is_valid_string_literal(token.text, p.spec);
|
return is_valid_string_literal(token.text, p.spec);
|
||||||
|
|
||||||
case Open_Brace:
|
case .Open_Brace:
|
||||||
return validate_object(p);
|
return validate_object(p);
|
||||||
|
|
||||||
case Open_Bracket:
|
case .Open_Bracket:
|
||||||
return validate_array(p);
|
return validate_array(p);
|
||||||
|
|
||||||
case:
|
case:
|
||||||
if p.spec == Specification.JSON5 {
|
if p.spec == Specification.JSON5 {
|
||||||
switch token.kind {
|
#partial switch token.kind {
|
||||||
case Infinity, NaN:
|
case .Infinity, .NaN:
|
||||||
advance_token(p);
|
advance_token(p);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-8
@@ -794,7 +794,7 @@ enum_value_to_string :: proc(val: any) -> (string, bool) {
|
|||||||
v.id = runtime.typeid_base(v.id);
|
v.id = runtime.typeid_base(v.id);
|
||||||
type_info := type_info_of(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: return "", false;
|
||||||
case runtime.Type_Info_Enum:
|
case runtime.Type_Info_Enum:
|
||||||
get_str :: proc(i: $T, e: runtime.Type_Info_Enum) -> (string, bool) {
|
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);
|
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: fmt_bad_verb(fi, verb);
|
||||||
case runtime.Type_Info_Enum:
|
case runtime.Type_Info_Enum:
|
||||||
switch verb {
|
switch verb {
|
||||||
@@ -898,7 +898,7 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
t := runtime.type_info_base(ti);
|
t := runtime.type_info_base(ti);
|
||||||
switch info in t.variant {
|
#partial switch info in t.variant {
|
||||||
case runtime.Type_Info_Integer:
|
case runtime.Type_Info_Integer:
|
||||||
switch info.endianness {
|
switch info.endianness {
|
||||||
case .Platform: return false;
|
case .Platform: return false;
|
||||||
@@ -912,7 +912,7 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") {
|
|||||||
byte_swap :: bits.byte_swap;
|
byte_swap :: bits.byte_swap;
|
||||||
|
|
||||||
type_info := type_info_of(v.id);
|
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:
|
case runtime.Type_Info_Named:
|
||||||
val := v;
|
val := v;
|
||||||
val.id = info.base.id;
|
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 = "") {
|
fmt_bit_field :: proc(fi: ^Info, v: any, bit_field_name: string = "") {
|
||||||
type_info := type_info_of(v.id);
|
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:
|
case runtime.Type_Info_Named:
|
||||||
val := v;
|
val := v;
|
||||||
val.id = info.base.id;
|
val.id = info.base.id;
|
||||||
@@ -1052,7 +1052,7 @@ fmt_opaque :: proc(fi: ^Info, v: any) {
|
|||||||
strings.write_byte(fi.buf, '{');
|
strings.write_byte(fi.buf, '{');
|
||||||
defer 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:
|
case rt.Type_Info_Integer, rt.Type_Info_Pointer, rt.Type_Info_Float:
|
||||||
fmt_value(fi, any{v.data, elem.id}, 'v');
|
fmt_value(fi, any{v.data, elem.id}, 'v');
|
||||||
case:
|
case:
|
||||||
@@ -1073,8 +1073,11 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
|||||||
|
|
||||||
type_info := type_info_of(v.id);
|
type_info := type_info_of(v.id);
|
||||||
switch info in type_info.variant {
|
switch info in type_info.variant {
|
||||||
|
case runtime.Type_Info_Any: // Ignore
|
||||||
|
case runtime.Type_Info_Tuple: // Ignore
|
||||||
|
|
||||||
case runtime.Type_Info_Named:
|
case runtime.Type_Info_Named:
|
||||||
switch b in info.base.variant {
|
#partial switch b in info.base.variant {
|
||||||
case runtime.Type_Info_Struct:
|
case runtime.Type_Info_Struct:
|
||||||
if verb != 'v' {
|
if verb != 'v' {
|
||||||
fmt_bad_verb(fi, verb);
|
fmt_bad_verb(fi, verb);
|
||||||
@@ -1193,7 +1196,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
|||||||
a := any{ptr, info.elem.id};
|
a := any{ptr, info.elem.id};
|
||||||
|
|
||||||
elem := runtime.type_info_base(info.elem);
|
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,
|
case runtime.Type_Info_Array,
|
||||||
runtime.Type_Info_Slice,
|
runtime.Type_Info_Slice,
|
||||||
runtime.Type_Info_Dynamic_Array,
|
runtime.Type_Info_Dynamic_Array,
|
||||||
|
|||||||
@@ -331,7 +331,7 @@ Switch_Stmt :: struct {
|
|||||||
init: ^Stmt,
|
init: ^Stmt,
|
||||||
cond: ^Expr,
|
cond: ^Expr,
|
||||||
body: ^Stmt,
|
body: ^Stmt,
|
||||||
complete: bool,
|
partial: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
Type_Switch_Stmt :: struct {
|
Type_Switch_Stmt :: struct {
|
||||||
@@ -341,7 +341,7 @@ Type_Switch_Stmt :: struct {
|
|||||||
tag: ^Stmt,
|
tag: ^Stmt,
|
||||||
expr: ^Expr,
|
expr: ^Expr,
|
||||||
body: ^Stmt,
|
body: ^Stmt,
|
||||||
complete: bool,
|
partial: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
Branch_Stmt :: struct {
|
Branch_Stmt :: struct {
|
||||||
|
|||||||
@@ -390,7 +390,7 @@ expect_semicolon :: proc(p: ^Parser, node: ^ast.Node) -> bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch p.curr_tok.kind {
|
#partial switch p.curr_tok.kind {
|
||||||
case .Close_Brace:
|
case .Close_Brace:
|
||||||
case .Close_Paren:
|
case .Close_Paren:
|
||||||
case .Else:
|
case .Else:
|
||||||
@@ -475,7 +475,7 @@ parse_when_stmt :: proc(p: ^Parser) -> ^ast.When_Stmt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if allow_token(p, .Else) {
|
if allow_token(p, .Else) {
|
||||||
switch p.curr_tok.kind {
|
#partial switch p.curr_tok.kind {
|
||||||
case .When:
|
case .When:
|
||||||
else_stmt = parse_when_stmt(p);
|
else_stmt = parse_when_stmt(p);
|
||||||
case .Open_Brace:
|
case .Open_Brace:
|
||||||
@@ -550,7 +550,7 @@ parse_if_stmt :: proc(p: ^Parser) -> ^ast.If_Stmt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if allow_token(p, .Else) {
|
if allow_token(p, .Else) {
|
||||||
switch p.curr_tok.kind {
|
#partial switch p.curr_tok.kind {
|
||||||
case .If:
|
case .If:
|
||||||
else_stmt = parse_if_stmt(p);
|
else_stmt = parse_if_stmt(p);
|
||||||
case .Open_Brace:
|
case .Open_Brace:
|
||||||
@@ -859,7 +859,7 @@ parse_foreign_block :: proc(p: ^Parser, tok: tokenizer.Token) -> ^ast.Foreign_Bl
|
|||||||
docs := p.lead_comment;
|
docs := p.lead_comment;
|
||||||
|
|
||||||
foreign_library: ^ast.Expr;
|
foreign_library: ^ast.Expr;
|
||||||
switch p.curr_tok.kind {
|
#partial switch p.curr_tok.kind {
|
||||||
case .Open_Brace:
|
case .Open_Brace:
|
||||||
i := ast.new(ast.Ident, tok.pos, end_pos(tok));
|
i := ast.new(ast.Ident, tok.pos, end_pos(tok));
|
||||||
i.name = "_";
|
i.name = "_";
|
||||||
@@ -901,7 +901,7 @@ parse_foreign_decl :: proc(p: ^Parser) -> ^ast.Decl {
|
|||||||
docs := p.lead_comment;
|
docs := p.lead_comment;
|
||||||
tok := expect_token(p, .Foreign);
|
tok := expect_token(p, .Foreign);
|
||||||
|
|
||||||
switch p.curr_tok.kind {
|
#partial switch p.curr_tok.kind {
|
||||||
case .Ident, .Open_Brace:
|
case .Ident, .Open_Brace:
|
||||||
return parse_foreign_block(p, tok);
|
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 {
|
parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
||||||
switch p.curr_tok.kind {
|
#partial switch p.curr_tok.kind {
|
||||||
// Operands
|
// Operands
|
||||||
case .Context, // Also allows for 'context = '
|
case .Context, // Also allows for 'context = '
|
||||||
.Proc,
|
.Proc,
|
||||||
@@ -1086,12 +1086,12 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
|||||||
stmt.state_flags |= {.No_Bounds_Check};
|
stmt.state_flags |= {.No_Bounds_Check};
|
||||||
}
|
}
|
||||||
return stmt;
|
return stmt;
|
||||||
case "complete":
|
case "partial":
|
||||||
stmt := parse_stmt(p);
|
stmt := parse_stmt(p);
|
||||||
switch s in &stmt.derived {
|
switch s in &stmt.derived {
|
||||||
case ast.Switch_Stmt: s.complete = true;
|
case ast.Switch_Stmt: s.partial = true;
|
||||||
case ast.Type_Switch_Stmt: s.complete = true;
|
case ast.Type_Switch_Stmt: s.partial = true;
|
||||||
case: error(p, stmt.pos, "#complete can only be applied to a switch statement");
|
case: error(p, stmt.pos, "#partial can only be applied to a switch statement");
|
||||||
}
|
}
|
||||||
return stmt;
|
return stmt;
|
||||||
case "assert", "panic":
|
case "assert", "panic":
|
||||||
@@ -1130,7 +1130,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
|||||||
|
|
||||||
|
|
||||||
token_precedence :: proc(p: ^Parser, kind: tokenizer.Token_Kind) -> int {
|
token_precedence :: proc(p: ^Parser, kind: tokenizer.Token_Kind) -> int {
|
||||||
switch kind {
|
#partial switch kind {
|
||||||
case .Question:
|
case .Question:
|
||||||
return 1;
|
return 1;
|
||||||
case .Ellipsis, .Range_Half:
|
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 {
|
is_token_field_prefix :: proc(p: ^Parser) -> Field_Prefix {
|
||||||
using Field_Prefix;
|
using Field_Prefix;
|
||||||
switch p.curr_tok.kind {
|
#partial switch p.curr_tok.kind {
|
||||||
case .EOF:
|
case .EOF:
|
||||||
return Invalid;
|
return Invalid;
|
||||||
case .Using:
|
case .Using:
|
||||||
@@ -1323,7 +1323,7 @@ is_token_field_prefix :: proc(p: ^Parser) -> Field_Prefix {
|
|||||||
case .Hash:
|
case .Hash:
|
||||||
advance_token(p);
|
advance_token(p);
|
||||||
defer advance_token(p);
|
defer advance_token(p);
|
||||||
switch p.curr_tok.kind {
|
#partial switch p.curr_tok.kind {
|
||||||
case .Ident:
|
case .Ident:
|
||||||
switch p.curr_tok.text {
|
switch p.curr_tok.text {
|
||||||
case "no_alias":
|
case "no_alias":
|
||||||
@@ -1359,7 +1359,7 @@ parse_field_prefixes :: proc(p: ^Parser) -> ast.Field_Flags {
|
|||||||
for kind in Field_Prefix {
|
for kind in Field_Prefix {
|
||||||
count := counts[kind];
|
count := counts[kind];
|
||||||
using Field_Prefix;
|
using Field_Prefix;
|
||||||
#complete switch kind {
|
switch kind {
|
||||||
case Invalid, Unknown: // Ignore
|
case Invalid, Unknown: // Ignore
|
||||||
case Using:
|
case Using:
|
||||||
if count > 1 do error(p, p.curr_tok.pos, "multiple 'using' in this field list");
|
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 {
|
for flag in ast.Field_Flag {
|
||||||
if flag notin allowed_flags && flag in flags {
|
if flag notin allowed_flags && flag in flags {
|
||||||
#complete switch flag {
|
switch flag {
|
||||||
case .Using:
|
case .Using:
|
||||||
error(p, p.curr_tok.pos, "'using' is not allowed within this field list");
|
error(p, p.curr_tok.pos, "'using' is not allowed within this field list");
|
||||||
case .No_Alias:
|
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 {
|
parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
||||||
switch p.curr_tok.kind {
|
#partial switch p.curr_tok.kind {
|
||||||
case .Ident:
|
case .Ident:
|
||||||
return parse_ident(p);
|
return parse_ident(p);
|
||||||
|
|
||||||
@@ -1945,7 +1945,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
|||||||
expr := parse_unary_expr(p, lhs);
|
expr := parse_unary_expr(p, lhs);
|
||||||
|
|
||||||
pi := ast.Proc_Inlining.None;
|
pi := ast.Proc_Inlining.None;
|
||||||
switch tok.kind {
|
#partial switch tok.kind {
|
||||||
case .Inline:
|
case .Inline:
|
||||||
pi = ast.Proc_Inlining.Inline;
|
pi = ast.Proc_Inlining.Inline;
|
||||||
case .No_Inline:
|
case .No_Inline:
|
||||||
@@ -2537,7 +2537,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
|
|||||||
loop := true;
|
loop := true;
|
||||||
is_lhs := lhs;
|
is_lhs := lhs;
|
||||||
for loop {
|
for loop {
|
||||||
switch p.curr_tok.kind {
|
#partial switch p.curr_tok.kind {
|
||||||
case:
|
case:
|
||||||
loop = false;
|
loop = false;
|
||||||
|
|
||||||
@@ -2556,7 +2556,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
|
|||||||
p.expr_level += 1;
|
p.expr_level += 1;
|
||||||
open := expect_token(p, .Open_Bracket);
|
open := expect_token(p, .Open_Bracket);
|
||||||
|
|
||||||
switch p.curr_tok.kind {
|
#partial switch p.curr_tok.kind {
|
||||||
case .Colon, .Ellipsis, .Range_Half:
|
case .Colon, .Ellipsis, .Range_Half:
|
||||||
// NOTE(bill): Do not err yet
|
// NOTE(bill): Do not err yet
|
||||||
break;
|
break;
|
||||||
@@ -2564,7 +2564,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
|
|||||||
indicies[0] = parse_expr(p, false);
|
indicies[0] = parse_expr(p, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch p.curr_tok.kind {
|
#partial switch p.curr_tok.kind {
|
||||||
case .Ellipsis, .Range_Half:
|
case .Ellipsis, .Range_Half:
|
||||||
error(p, p.curr_tok.pos, "expected a colon, not a range");
|
error(p, p.curr_tok.pos, "expected a colon, not a range");
|
||||||
fallthrough;
|
fallthrough;
|
||||||
@@ -2602,7 +2602,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
|
|||||||
|
|
||||||
case .Period:
|
case .Period:
|
||||||
tok := expect_token(p, .Period);
|
tok := expect_token(p, .Period);
|
||||||
switch p.curr_tok.kind {
|
#partial switch p.curr_tok.kind {
|
||||||
case .Ident:
|
case .Ident:
|
||||||
field := parse_ident(p);
|
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);
|
return parse_binary_expr(p, lhs, 0+1);
|
||||||
}
|
}
|
||||||
parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
||||||
switch p.curr_tok.kind {
|
#partial switch p.curr_tok.kind {
|
||||||
case .Transmute, .Cast:
|
case .Transmute, .Cast:
|
||||||
tok := advance_token(p);
|
tok := advance_token(p);
|
||||||
open := expect_token(p, .Open_Paren);
|
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:
|
case op.kind == .Colon:
|
||||||
expect_token_after(p, .Colon, "identifier list");
|
expect_token_after(p, .Colon, "identifier list");
|
||||||
if .Label in flags && len(lhs) == 1 {
|
if .Label in flags && len(lhs) == 1 {
|
||||||
switch p.curr_tok.kind {
|
#partial switch p.curr_tok.kind {
|
||||||
case .Open_Brace, .If, .For, .Switch:
|
case .Open_Brace, .If, .For, .Switch:
|
||||||
label := lhs[0];
|
label := lhs[0];
|
||||||
stmt := parse_stmt(p);
|
stmt := parse_stmt(p);
|
||||||
@@ -2847,7 +2847,7 @@ parse_value_decl :: proc(p: ^Parser, names: []^ast.Expr, docs: ^ast.Comment_Grou
|
|||||||
values: []^ast.Expr;
|
values: []^ast.Expr;
|
||||||
type := parse_type_or_ident(p);
|
type := parse_type_or_ident(p);
|
||||||
|
|
||||||
switch p.curr_tok.kind {
|
#partial switch p.curr_tok.kind {
|
||||||
case .Eq, .Colon:
|
case .Eq, .Colon:
|
||||||
sep := advance_token(p);
|
sep := advance_token(p);
|
||||||
is_mutable = sep.kind != .Colon;
|
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;
|
import_name: tokenizer.Token;
|
||||||
is_using := kind != Import_Decl_Kind.Standard;
|
is_using := kind != Import_Decl_Kind.Standard;
|
||||||
|
|
||||||
switch p.curr_tok.kind {
|
#partial switch p.curr_tok.kind {
|
||||||
case .Ident:
|
case .Ident:
|
||||||
import_name = advance_token(p);
|
import_name = advance_token(p);
|
||||||
case:
|
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;
|
return Token_Kind.B_Literal_Begin < kind && kind < Token_Kind.B_Literal_End;
|
||||||
}
|
}
|
||||||
is_operator :: proc(kind: Token_Kind) -> bool {
|
is_operator :: proc(kind: Token_Kind) -> bool {
|
||||||
switch kind {
|
#partial switch kind {
|
||||||
case .B_Operator_Begin .. .B_Operator_End:
|
case .B_Operator_Begin .. .B_Operator_End:
|
||||||
return true;
|
return true;
|
||||||
case .In, .Notin:
|
case .In, .Notin:
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ Type_Kind :: enum {
|
|||||||
type_kind :: proc(T: typeid) -> Type_Kind {
|
type_kind :: proc(T: typeid) -> Type_Kind {
|
||||||
ti := type_info_of(T);
|
ti := type_info_of(T);
|
||||||
if ti != nil {
|
if ti != nil {
|
||||||
#complete switch _ in ti.variant {
|
switch _ in ti.variant {
|
||||||
case runtime.Type_Info_Named: return .Named;
|
case runtime.Type_Info_Named: return .Named;
|
||||||
case runtime.Type_Info_Integer: return .Integer;
|
case runtime.Type_Info_Integer: return .Integer;
|
||||||
case runtime.Type_Info_Rune: return .Rune;
|
case runtime.Type_Info_Rune: return .Rune;
|
||||||
|
|||||||
+14
-2
@@ -40,6 +40,14 @@ are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
|
|||||||
_, ok := b.variant.(rt.Type_Info_Complex);
|
_, ok := b.variant.(rt.Type_Info_Complex);
|
||||||
return ok;
|
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:
|
case rt.Type_Info_String:
|
||||||
_, ok := b.variant.(rt.Type_Info_String);
|
_, ok := b.variant.(rt.Type_Info_String);
|
||||||
return ok;
|
return ok;
|
||||||
@@ -174,7 +182,7 @@ are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
|
|||||||
|
|
||||||
is_signed :: proc(info: ^rt.Type_Info) -> bool {
|
is_signed :: proc(info: ^rt.Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
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_Integer: return i.signed;
|
||||||
case rt.Type_Info_Float: return true;
|
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_byte(buf, info.signed ? 'i' : 'u');
|
||||||
write_i64(buf, i64(8*ti.size), 10);
|
write_i64(buf, i64(8*ti.size), 10);
|
||||||
switch info.endianness {
|
switch info.endianness {
|
||||||
|
case .Platform: // Okay
|
||||||
case .Little: write_string(buf, "le");
|
case .Little: write_string(buf, "le");
|
||||||
case .Big: write_string(buf, "be");
|
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:
|
case rt.Type_Info_Complex:
|
||||||
write_string(buf, "complex");
|
write_string(buf, "complex");
|
||||||
write_i64(buf, i64(8*ti.size), 10);
|
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:
|
case rt.Type_Info_String:
|
||||||
if info.is_cstring {
|
if info.is_cstring {
|
||||||
write_string(buf, "cstring");
|
write_string(buf, "cstring");
|
||||||
@@ -399,7 +411,7 @@ write_type :: proc(buf: ^strings.Builder, ti: ^rt.Type_Info) {
|
|||||||
write_type(buf, info.value);
|
write_type(buf, info.value);
|
||||||
|
|
||||||
case rt.Type_Info_Struct:
|
case rt.Type_Info_Struct:
|
||||||
#complete switch info.soa_kind {
|
switch info.soa_kind {
|
||||||
case .None: // Ignore
|
case .None: // Ignore
|
||||||
case .Fixed:
|
case .Fixed:
|
||||||
write_string(buf, "#soa[");
|
write_string(buf, "#soa[");
|
||||||
|
|||||||
@@ -305,7 +305,7 @@ type_info_base :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
|
|||||||
|
|
||||||
base := info;
|
base := info;
|
||||||
loop: for {
|
loop: for {
|
||||||
switch i in base.variant {
|
#partial switch i in base.variant {
|
||||||
case Type_Info_Named: base = i.base;
|
case Type_Info_Named: base = i.base;
|
||||||
case: break loop;
|
case: break loop;
|
||||||
}
|
}
|
||||||
@@ -319,7 +319,7 @@ type_info_core :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
|
|||||||
|
|
||||||
base := info;
|
base := info;
|
||||||
loop: for {
|
loop: for {
|
||||||
switch i in base.variant {
|
#partial switch i in base.variant {
|
||||||
case Type_Info_Named: base = i.base;
|
case Type_Info_Named: base = i.base;
|
||||||
case Type_Info_Enum: base = i.base;
|
case Type_Info_Enum: base = i.base;
|
||||||
case Type_Info_Opaque: base = i.elem;
|
case Type_Info_Opaque: base = i.elem;
|
||||||
|
|||||||
@@ -110,6 +110,9 @@ print_type :: proc(fd: os.Handle, ti: ^Type_Info) {
|
|||||||
case Type_Info_Complex:
|
case Type_Info_Complex:
|
||||||
os.write_string(fd, "complex");
|
os.write_string(fd, "complex");
|
||||||
print_u64(fd, u64(8*ti.size));
|
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:
|
case Type_Info_String:
|
||||||
os.write_string(fd, "string");
|
os.write_string(fd, "string");
|
||||||
case Type_Info_Boolean:
|
case Type_Info_Boolean:
|
||||||
@@ -183,7 +186,7 @@ print_type :: proc(fd: os.Handle, ti: ^Type_Info) {
|
|||||||
print_type(fd, info.value);
|
print_type(fd, info.value);
|
||||||
|
|
||||||
case Type_Info_Struct:
|
case Type_Info_Struct:
|
||||||
#complete switch info.soa_kind {
|
switch info.soa_kind {
|
||||||
case .None: // Ignore
|
case .None: // Ignore
|
||||||
case .Fixed:
|
case .Fixed:
|
||||||
os.write_string(fd, "#soa[");
|
os.write_string(fd, "#soa[");
|
||||||
@@ -263,7 +266,7 @@ print_type :: proc(fd: os.Handle, ti: ^Type_Info) {
|
|||||||
case Type_Info_Bit_Set:
|
case Type_Info_Bit_Set:
|
||||||
os.write_string(fd, "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:
|
case Type_Info_Enum:
|
||||||
print_type(fd, info.elem);
|
print_type(fd, info.elem);
|
||||||
case Type_Info_Rune:
|
case Type_Info_Rune:
|
||||||
|
|||||||
+11
-11
@@ -11,7 +11,7 @@ Ordering :: enum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
strongest_failure_ordering :: inline proc "contextless" (order: Ordering) -> Ordering {
|
strongest_failure_ordering :: inline proc "contextless" (order: Ordering) -> Ordering {
|
||||||
#complete switch order {
|
switch order {
|
||||||
case .Relaxed: return .Relaxed;
|
case .Relaxed: return .Relaxed;
|
||||||
case .Release: return .Relaxed;
|
case .Release: return .Relaxed;
|
||||||
case .Acquire: return .Acquire;
|
case .Acquire: return .Acquire;
|
||||||
@@ -22,7 +22,7 @@ strongest_failure_ordering :: inline proc "contextless" (order: Ordering) -> Ord
|
|||||||
}
|
}
|
||||||
|
|
||||||
fence :: inline proc "contextless" ($order: Ordering) {
|
fence :: inline proc "contextless" ($order: Ordering) {
|
||||||
#complete switch order {
|
switch order {
|
||||||
case .Relaxed: panic("there is no such thing as a relaxed fence");
|
case .Relaxed: panic("there is no such thing as a relaxed fence");
|
||||||
case .Release: intrinsics.atomic_fence_rel();
|
case .Release: intrinsics.atomic_fence_rel();
|
||||||
case .Acquire: intrinsics.atomic_fence_acq();
|
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) {
|
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 .Relaxed: intrinsics.atomic_store_relaxed(dst, val);
|
||||||
case .Release: intrinsics.atomic_store_rel(dst, val);
|
case .Release: intrinsics.atomic_store_rel(dst, val);
|
||||||
case .Sequentially_Consistent: intrinsics.atomic_store(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 {
|
atomic_load :: inline proc "contextless" (dst: ^$T, $order: Ordering) -> T {
|
||||||
#complete switch order {
|
switch order {
|
||||||
case .Relaxed: return intrinsics.atomic_load_relaxed(dst);
|
case .Relaxed: return intrinsics.atomic_load_relaxed(dst);
|
||||||
case .Acquire: return intrinsics.atomic_load_acq(dst);
|
case .Acquire: return intrinsics.atomic_load_acq(dst);
|
||||||
case .Sequentially_Consistent: return intrinsics.atomic_load(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 {
|
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 .Relaxed: return intrinsics.atomic_xchg_relaxed(dst, val);
|
||||||
case .Release: return intrinsics.atomic_xchg_rel(dst, val);
|
case .Release: return intrinsics.atomic_xchg_rel(dst, val);
|
||||||
case .Acquire: return intrinsics.atomic_xchg_acq(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 {
|
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 .Relaxed: return intrinsics.atomic_add_relaxed(dst, val);
|
||||||
case .Release: return intrinsics.atomic_add_rel(dst, val);
|
case .Release: return intrinsics.atomic_add_rel(dst, val);
|
||||||
case .Acquire: return intrinsics.atomic_add_acq(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 {
|
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 .Relaxed: return intrinsics.atomic_sub_relaxed(dst, val);
|
||||||
case .Release: return intrinsics.atomic_sub_rel(dst, val);
|
case .Release: return intrinsics.atomic_sub_rel(dst, val);
|
||||||
case .Acquire: return intrinsics.atomic_sub_acq(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 {
|
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 .Relaxed: return intrinsics.atomic_and_relaxed(dst, val);
|
||||||
case .Release: return intrinsics.atomic_and_rel(dst, val);
|
case .Release: return intrinsics.atomic_and_rel(dst, val);
|
||||||
case .Acquire: return intrinsics.atomic_and_acq(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 {
|
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 .Relaxed: return intrinsics.atomic_nand_relaxed(dst, val);
|
||||||
case .Release: return intrinsics.atomic_nand_rel(dst, val);
|
case .Release: return intrinsics.atomic_nand_rel(dst, val);
|
||||||
case .Acquire: return intrinsics.atomic_nand_acq(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 {
|
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 .Relaxed: return intrinsics.atomic_or_relaxed(dst, val);
|
||||||
case .Release: return intrinsics.atomic_or_rel(dst, val);
|
case .Release: return intrinsics.atomic_or_rel(dst, val);
|
||||||
case .Acquire: return intrinsics.atomic_or_acq(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 {
|
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 .Relaxed: return intrinsics.atomic_xor_relaxed(dst, val);
|
||||||
case .Release: return intrinsics.atomic_xor_rel(dst, val);
|
case .Release: return intrinsics.atomic_xor_rel(dst, val);
|
||||||
case .Acquire: return intrinsics.atomic_xor_acq(dst, val);
|
case .Acquire: return intrinsics.atomic_xor_acq(dst, val);
|
||||||
|
|||||||
+15
-5
@@ -7,6 +7,7 @@ import "core:thread"
|
|||||||
import "core:reflect"
|
import "core:reflect"
|
||||||
import "intrinsics"
|
import "intrinsics"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The Odin programming language is fast, concise, readable, pragmatic and open sourced.
|
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:
|
It is designed with the intent of replacing C with the following goals:
|
||||||
@@ -1233,8 +1234,8 @@ implicit_selector_expression :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
complete_switch :: proc() {
|
partial_switch :: proc() {
|
||||||
fmt.println("\n# complete_switch");
|
fmt.println("\n# partial_switch");
|
||||||
{ // enum
|
{ // enum
|
||||||
Foo :: enum {
|
Foo :: enum {
|
||||||
A,
|
A,
|
||||||
@@ -1244,22 +1245,31 @@ complete_switch :: proc() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
f := Foo.A;
|
f := Foo.A;
|
||||||
#complete switch f {
|
switch f {
|
||||||
case .A: fmt.println("A");
|
case .A: fmt.println("A");
|
||||||
case .B: fmt.println("B");
|
case .B: fmt.println("B");
|
||||||
case .C: fmt.println("C");
|
case .C: fmt.println("C");
|
||||||
case .D: fmt.println("D");
|
case .D: fmt.println("D");
|
||||||
case: fmt.println("?");
|
case: fmt.println("?");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#partial switch f {
|
||||||
|
case .A: fmt.println("A");
|
||||||
|
case .D: fmt.println("D");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
{ // union
|
{ // union
|
||||||
Foo :: union {int, bool};
|
Foo :: union {int, bool};
|
||||||
f: Foo = 123;
|
f: Foo = 123;
|
||||||
#complete switch in f {
|
switch in f {
|
||||||
case int: fmt.println("int");
|
case int: fmt.println("int");
|
||||||
case bool: fmt.println("bool");
|
case bool: fmt.println("bool");
|
||||||
case:
|
case:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#partial switch in f {
|
||||||
|
case bool: fmt.println("bool");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1820,7 +1830,7 @@ main :: proc() {
|
|||||||
array_programming();
|
array_programming();
|
||||||
map_type();
|
map_type();
|
||||||
implicit_selector_expression();
|
implicit_selector_expression();
|
||||||
complete_switch();
|
partial_switch();
|
||||||
cstring_example();
|
cstring_example();
|
||||||
bit_set_type();
|
bit_set_type();
|
||||||
deferred_procedure_associations();
|
deferred_procedure_associations();
|
||||||
|
|||||||
+25
-34
@@ -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)) {
|
if (!is_type_enum(x.type)) {
|
||||||
error(x.expr, "#complete switch statement can be only used with an enum type");
|
error(x.expr, "#partial switch statement can be only used with an enum type");
|
||||||
complete = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -877,9 +876,6 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
|||||||
Operand a1 = lhs;
|
Operand a1 = lhs;
|
||||||
Operand b1 = rhs;
|
Operand b1 = rhs;
|
||||||
check_comparison(ctx, &a1, &b1, Token_LtEq);
|
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);
|
add_constant_switch_case(ctx, &seen, lhs);
|
||||||
if (upper_op == Token_GtEq) {
|
if (upper_op == Token_GtEq) {
|
||||||
@@ -926,9 +922,6 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (y.mode != Addressing_Constant) {
|
if (y.mode != Addressing_Constant) {
|
||||||
if (complete) {
|
|
||||||
error(y.expr, "#complete switch statement only allows constant case clauses");
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -942,7 +935,7 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
|||||||
check_close_scope(ctx);
|
check_close_scope(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (complete) {
|
if (!is_partial && is_type_enum(x.type)) {
|
||||||
Type *et = base_type(x.type);
|
Type *et = base_type(x.type);
|
||||||
GB_ASSERT(is_type_enum(et));
|
GB_ASSERT(is_type_enum(et));
|
||||||
auto fields = et->Enum.fields;
|
auto fields = et->Enum.fields;
|
||||||
@@ -968,18 +961,17 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
|||||||
defer (begin_error_block());
|
defer (begin_error_block());
|
||||||
|
|
||||||
if (unhandled.count == 1) {
|
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 {
|
} else {
|
||||||
error_no_newline(node, "Unhandled switch cases: ");
|
error_no_newline(node, "Unhandled switch cases: ");
|
||||||
}
|
for_array(i, unhandled) {
|
||||||
for_array(i, unhandled) {
|
Entity *f = unhandled[i];
|
||||||
Entity *f = unhandled[i];
|
error_line("\t%.*s\n", LIT(f->token.string));
|
||||||
if (i > 0) {
|
|
||||||
error_line(", ");
|
|
||||||
}
|
}
|
||||||
error_line("%.*s", LIT(f->token.string));
|
|
||||||
}
|
}
|
||||||
error_line("\n");
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool complete = ss->complete;
|
bool is_partial = ss->partial;
|
||||||
if (complete) {
|
if (is_partial) {
|
||||||
if (switch_kind != TypeSwitch_Union) {
|
if (switch_kind != TypeSwitch_Union) {
|
||||||
error(node, "#complete switch statement may only be used with a union");
|
error(node, "#partial switch statement may only be used with a union");
|
||||||
complete = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1174,7 +1165,7 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
|||||||
check_close_scope(ctx);
|
check_close_scope(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (complete) {
|
if (!is_partial && is_type_union(type_deref(x.type))) {
|
||||||
Type *ut = base_type(type_deref(x.type));
|
Type *ut = base_type(type_deref(x.type));
|
||||||
GB_ASSERT(is_type_union(ut));
|
GB_ASSERT(is_type_union(ut));
|
||||||
auto variants = ut->Union.variants;
|
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 > 0) {
|
||||||
if (unhandled.count == 1) {
|
if (unhandled.count == 1) {
|
||||||
error_no_newline(node, "Unhandled switch case: ");
|
gbString s = type_to_string(unhandled[0]);
|
||||||
} else {
|
error_no_newline(node, "Unhandled switch case: %s", s);
|
||||||
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);
|
|
||||||
gb_string_free(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("\n");
|
||||||
|
error_line("\tSuggestion: Was '#partial switch' wanted? This replaces the previous '#complete switch'.\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-2
@@ -766,6 +766,7 @@ Ast *ast_switch_stmt(AstFile *f, Token token, Ast *init, Ast *tag, Ast *body) {
|
|||||||
result->SwitchStmt.init = init;
|
result->SwitchStmt.init = init;
|
||||||
result->SwitchStmt.tag = tag;
|
result->SwitchStmt.tag = tag;
|
||||||
result->SwitchStmt.body = body;
|
result->SwitchStmt.body = body;
|
||||||
|
result->SwitchStmt.partial = false;
|
||||||
return result;
|
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.token = token;
|
||||||
result->TypeSwitchStmt.tag = tag;
|
result->TypeSwitchStmt.tag = tag;
|
||||||
result->TypeSwitchStmt.body = body;
|
result->TypeSwitchStmt.body = body;
|
||||||
|
result->TypeSwitchStmt.partial = false;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4060,16 +4062,32 @@ Ast *parse_stmt(AstFile *f) {
|
|||||||
s = parse_stmt(f);
|
s = parse_stmt(f);
|
||||||
switch (s->kind) {
|
switch (s->kind) {
|
||||||
case Ast_SwitchStmt:
|
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;
|
break;
|
||||||
case Ast_TypeSwitchStmt:
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
syntax_error(token, "#complete can only be applied to a switch statement");
|
syntax_error(token, "#complete can only be applied to a switch statement");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return s;
|
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") {
|
} else if (tag == "assert") {
|
||||||
Ast *t = ast_basic_directive(f, hash_token, tag);
|
Ast *t = ast_basic_directive(f, hash_token, tag);
|
||||||
return ast_expr_stmt(f, parse_call_expr(f, t));
|
return ast_expr_stmt(f, parse_call_expr(f, t));
|
||||||
|
|||||||
+12
-12
@@ -363,20 +363,20 @@ AST_KIND(_ComplexStmtBegin, "", bool) \
|
|||||||
Entity *implicit_entity; \
|
Entity *implicit_entity; \
|
||||||
}) \
|
}) \
|
||||||
AST_KIND(SwitchStmt, "switch statement", struct { \
|
AST_KIND(SwitchStmt, "switch statement", struct { \
|
||||||
Token token; \
|
Token token; \
|
||||||
Ast *label; \
|
Ast *label; \
|
||||||
Ast *init; \
|
Ast *init; \
|
||||||
Ast *tag; \
|
Ast *tag; \
|
||||||
Ast *body; \
|
Ast *body; \
|
||||||
bool complete; \
|
bool partial; \
|
||||||
}) \
|
}) \
|
||||||
AST_KIND(TypeSwitchStmt, "type switch statement", struct { \
|
AST_KIND(TypeSwitchStmt, "type switch statement", struct { \
|
||||||
Token token; \
|
Token token; \
|
||||||
Ast *label; \
|
Ast *label; \
|
||||||
Ast *tag; \
|
Ast *tag; \
|
||||||
Ast *body; \
|
Ast *body; \
|
||||||
bool complete; \
|
bool partial; \
|
||||||
}) \
|
}) \
|
||||||
AST_KIND(DeferStmt, "defer statement", struct { Token token; Ast *stmt; }) \
|
AST_KIND(DeferStmt, "defer statement", struct { Token token; Ast *stmt; }) \
|
||||||
AST_KIND(BranchStmt, "branch statement", struct { Token token; Ast *label; }) \
|
AST_KIND(BranchStmt, "branch statement", struct { Token token; Ast *label; }) \
|
||||||
AST_KIND(UsingStmt, "using statement", struct { \
|
AST_KIND(UsingStmt, "using statement", struct { \
|
||||||
|
|||||||
Reference in New Issue
Block a user