Kaynağa Gözat

Update `core:odin/*` for `or_else` and `or_return`

gingerBill 4 yıl önce
ebeveyn
işleme
4e1c9b71f4

+ 15 - 11
core/odin/ast/ast.odin

@@ -241,15 +241,6 @@ Field_Value :: struct {
 	value: ^Expr,
 	value: ^Expr,
 }
 }
 
 
-Ternary_Expr :: struct {
-	using node: Expr,
-	cond: ^Expr,
-	op1:  tokenizer.Token,
-	x:    ^Expr,
-	op2:  tokenizer.Token,
-	y:    ^Expr,
-}
-
 Ternary_If_Expr :: struct {
 Ternary_If_Expr :: struct {
 	using node: Expr,
 	using node: Expr,
 	x:    ^Expr,
 	x:    ^Expr,
@@ -261,13 +252,26 @@ Ternary_If_Expr :: struct {
 
 
 Ternary_When_Expr :: struct {
 Ternary_When_Expr :: struct {
 	using node: Expr,
 	using node: Expr,
-	x: ^Expr,
+	x:    ^Expr,
 	op1:  tokenizer.Token,
 	op1:  tokenizer.Token,
 	cond: ^Expr,
 	cond: ^Expr,
 	op2:  tokenizer.Token,
 	op2:  tokenizer.Token,
 	y:    ^Expr,
 	y:    ^Expr,
 }
 }
 
 
+Or_Else_Expr :: struct {
+	using node: Expr,
+	x:     ^Expr,
+	token: tokenizer.Token,
+	y:     ^Expr,
+}
+
+Or_Return_Expr :: struct {
+	using node: Expr,
+	expr:  ^Expr,
+	token: tokenizer.Token,
+}
+
 Type_Assertion :: struct {
 Type_Assertion :: struct {
 	using node: Expr,
 	using node: Expr,
 	expr:  ^Expr,
 	expr:  ^Expr,
@@ -542,7 +546,7 @@ Field_Flag :: enum {
 	No_Alias,
 	No_Alias,
 	C_Vararg,
 	C_Vararg,
 	Auto_Cast,
 	Auto_Cast,
-	In,
+	Any_Int,
 
 
 	Results,
 	Results,
 	Tags,
 	Tags,

+ 5 - 4
core/odin/ast/clone.odin

@@ -129,10 +129,6 @@ clone_node :: proc(node: ^Node) -> ^Node {
 	case Field_Value:
 	case Field_Value:
 		r.field = clone(r.field);
 		r.field = clone(r.field);
 		r.value = clone(r.value);
 		r.value = clone(r.value);
-	case Ternary_Expr:
-		r.cond = clone(r.cond);
-		r.x    = clone(r.x);
-		r.y    = clone(r.y);
 	case Ternary_If_Expr:
 	case Ternary_If_Expr:
 		r.x    = clone(r.x);
 		r.x    = clone(r.x);
 		r.cond = clone(r.cond);
 		r.cond = clone(r.cond);
@@ -141,6 +137,11 @@ clone_node :: proc(node: ^Node) -> ^Node {
 		r.x    = clone(r.x);
 		r.x    = clone(r.x);
 		r.cond = clone(r.cond);
 		r.cond = clone(r.cond);
 		r.y    = clone(r.y);
 		r.y    = clone(r.y);
+	case Or_Else_Expr:
+		r.x    = clone(r.x);
+		r.y    = clone(r.y);
+	case Or_Return_Expr:
+		r.expr = clone(r.expr);
 	case Type_Assertion:
 	case Type_Assertion:
 		r.expr = clone(r.expr);
 		r.expr = clone(r.expr);
 		r.type = clone(r.type);
 		r.type = clone(r.type);

+ 5 - 4
core/odin/ast/walk.odin

@@ -126,10 +126,6 @@ walk :: proc(v: ^Visitor, node: ^Node) {
 	case Field_Value:
 	case Field_Value:
 		walk(v, n.field);
 		walk(v, n.field);
 		walk(v, n.value);
 		walk(v, n.value);
-	case Ternary_Expr:
-		walk(v, n.cond);
-		walk(v, n.x);
-		walk(v, n.y);
 	case Ternary_If_Expr:
 	case Ternary_If_Expr:
 		walk(v, n.x);
 		walk(v, n.x);
 		walk(v, n.cond);
 		walk(v, n.cond);
@@ -138,6 +134,11 @@ walk :: proc(v: ^Visitor, node: ^Node) {
 		walk(v, n.x);
 		walk(v, n.x);
 		walk(v, n.cond);
 		walk(v, n.cond);
 		walk(v, n.y);
 		walk(v, n.y);
+	case Or_Else_Expr:
+		walk(v, n.x);
+		walk(v, n.y);
+	case Or_Return_Expr:
+		walk(v, n.expr);
 	case Type_Assertion:
 	case Type_Assertion:
 		walk(v, n.expr);
 		walk(v, n.expr);
 		if n.type != nil {
 		if n.type != nil {

+ 64 - 47
core/odin/parser/parser.odin

@@ -374,11 +374,14 @@ expect_token_after :: proc(p: ^Parser, kind: tokenizer.Token_Kind, msg: string)
 
 
 expect_operator :: proc(p: ^Parser) -> tokenizer.Token {
 expect_operator :: proc(p: ^Parser) -> tokenizer.Token {
 	prev := p.curr_tok;
 	prev := p.curr_tok;
-	if prev.kind == .If || prev.kind == .When {
+	#partial switch prev.kind {
+	case .If, .When, .Or_Else, .Or_Return:
 		// okay
 		// okay
-	} else if !tokenizer.is_operator(prev.kind) {
-		g := tokenizer.token_to_string(prev);
-		error(p, prev.pos, "expected an operator, got '%s'", g);
+	case:
+		if !tokenizer.is_operator(prev.kind) {
+			g := tokenizer.token_to_string(prev);
+			error(p, prev.pos, "expected an operator, got '%s'", g);
+		}
 	}
 	}
 	advance_token(p);
 	advance_token(p);
 	return prev;
 	return prev;
@@ -1366,9 +1369,9 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
 			stmt := parse_stmt(p);
 			stmt := parse_stmt(p);
 			switch name {
 			switch name {
 			case "bounds_check":
 			case "bounds_check":
-				stmt.state_flags |= {.Bounds_Check};
+				stmt.state_flags += {.Bounds_Check};
 			case "no_bounds_check":
 			case "no_bounds_check":
-				stmt.state_flags |= {.No_Bounds_Check};
+				stmt.state_flags += {.No_Bounds_Check};
 			}
 			}
 			return stmt;
 			return stmt;
 		case "partial":
 		case "partial":
@@ -1449,7 +1452,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 {
 	#partial switch kind {
 	#partial switch kind {
-	case .Question, .If, .When:
+	case .Question, .If, .When, .Or_Else, .Or_Return:
 		return 1;
 		return 1;
 	case .Ellipsis, .Range_Half, .Range_Full:
 	case .Ellipsis, .Range_Half, .Range_Full:
 		if !p.allow_range {
 		if !p.allow_range {
@@ -1578,8 +1581,8 @@ Field_Prefix :: enum {
 	Using,
 	Using,
 	No_Alias,
 	No_Alias,
 	C_Vararg,
 	C_Vararg,
-	In,
 	Auto_Cast,
 	Auto_Cast,
+	Any_Int,
 }
 }
 
 
 Field_Prefixes :: distinct bit_set[Field_Prefix];
 Field_Prefixes :: distinct bit_set[Field_Prefix];
@@ -1626,19 +1629,15 @@ 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;
 	#partial switch p.curr_tok.kind {
 	#partial switch p.curr_tok.kind {
 	case .EOF:
 	case .EOF:
-		return Invalid;
+		return .Invalid;
 	case .Using:
 	case .Using:
 		advance_token(p);
 		advance_token(p);
-		return Using;
-	case .In:
-		advance_token(p);
-		return In;
+		return .Using;
 	case .Auto_Cast:
 	case .Auto_Cast:
 		advance_token(p);
 		advance_token(p);
-		return Auto_Cast;
+		return .Auto_Cast;
 	case .Hash:
 	case .Hash:
 		advance_token(p);
 		advance_token(p);
 		defer advance_token(p);
 		defer advance_token(p);
@@ -1646,14 +1645,16 @@ is_token_field_prefix :: proc(p: ^Parser) -> Field_Prefix {
 		case .Ident:
 		case .Ident:
 			switch p.curr_tok.text {
 			switch p.curr_tok.text {
 			case "no_alias":
 			case "no_alias":
-				return No_Alias;
+				return .No_Alias;
 			case "c_vararg":
 			case "c_vararg":
-				return C_Vararg;
+				return .C_Vararg;
+			case "any_int":
+				return .Any_Int;
 			}
 			}
 		}
 		}
-		return Unknown;
+		return .Unknown;
 	}
 	}
-	return Invalid;
+	return .Invalid;
 }
 }
 
 
 parse_field_prefixes :: proc(p: ^Parser) -> ast.Field_Flags {
 parse_field_prefixes :: proc(p: ^Parser) -> ast.Field_Flags {
@@ -1677,24 +1678,23 @@ 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;
 		switch kind {
 		switch kind {
-		case Invalid, Unknown: // Ignore
-		case Using:
+		case .Invalid, .Unknown: // Ignore
+		case .Using:
 			if count > 1 { error(p, p.curr_tok.pos, "multiple 'using' in this field list"); }
 			if count > 1 { error(p, p.curr_tok.pos, "multiple 'using' in this field list"); }
-			if count > 0 { flags |= {.Using}; }
-		case No_Alias:
+			if count > 0 { flags += {.Using}; }
+		case .No_Alias:
 			if count > 1 { error(p, p.curr_tok.pos, "multiple '#no_alias' in this field list"); }
 			if count > 1 { error(p, p.curr_tok.pos, "multiple '#no_alias' in this field list"); }
-			if count > 0 { flags |= {.No_Alias}; }
-		case C_Vararg:
+			if count > 0 { flags += {.No_Alias}; }
+		case .C_Vararg:
 			if count > 1 { error(p, p.curr_tok.pos, "multiple '#c_vararg' in this field list"); }
 			if count > 1 { error(p, p.curr_tok.pos, "multiple '#c_vararg' in this field list"); }
-			if count > 0 { flags |= {.C_Vararg}; }
-		case In:
-			if count > 1 { error(p, p.curr_tok.pos, "multiple 'in' in this field list"); }
-			if count > 0 { flags |= {.In}; }
-		case Auto_Cast:
+			if count > 0 { flags += {.C_Vararg}; }
+		case .Auto_Cast:
 			if count > 1 { error(p, p.curr_tok.pos, "multiple 'auto_cast' in this field list"); }
 			if count > 1 { error(p, p.curr_tok.pos, "multiple 'auto_cast' in this field list"); }
-			if count > 0 { flags |= {.Auto_Cast}; }
+			if count > 0 { flags += {.Auto_Cast}; }
+		case .Any_Int:
+			if count > 1 { error(p, p.curr_tok.pos, "multiple '#any_int' in this field list"); }
+			if count > 0 { flags += {.Any_Int}; }
 		}
 		}
 	}
 	}
 
 
@@ -1705,7 +1705,7 @@ check_field_flag_prefixes :: proc(p: ^Parser, name_count: int, allowed_flags, se
 	flags = set_flags;
 	flags = set_flags;
 	if name_count > 1 && .Using in flags {
 	if name_count > 1 && .Using in flags {
 		error(p, p.curr_tok.pos, "cannot apply 'using' to more than one of the same type");
 		error(p, p.curr_tok.pos, "cannot apply 'using' to more than one of the same type");
-		flags &~= {.Using};
+		flags -= {.Using};
 	}
 	}
 
 
 	for flag in ast.Field_Flag {
 	for flag in ast.Field_Flag {
@@ -1719,12 +1719,12 @@ check_field_flag_prefixes :: proc(p: ^Parser, name_count: int, allowed_flags, se
 				error(p, p.curr_tok.pos, "'#c_vararg' is not allowed within this field list");
 				error(p, p.curr_tok.pos, "'#c_vararg' is not allowed within this field list");
 			case .Auto_Cast:
 			case .Auto_Cast:
 				error(p, p.curr_tok.pos, "'auto_cast' is not allowed within this field list");
 				error(p, p.curr_tok.pos, "'auto_cast' is not allowed within this field list");
-			case .In:
-				error(p, p.curr_tok.pos, "'in' is not allowed within this field list");
+			case .Any_Int:
+				error(p, p.curr_tok.pos, "'#any_int' is not allowed within this field list");
 			case .Tags, .Ellipsis, .Results, .Default_Parameters, .Typeid_Token:
 			case .Tags, .Ellipsis, .Results, .Default_Parameters, .Typeid_Token:
 				panic("Impossible prefixes");
 				panic("Impossible prefixes");
 			}
 			}
-			flags &~= {flag};
+			flags -= {flag};
 		}
 		}
 	}
 	}
 
 
@@ -2062,10 +2062,10 @@ parse_proc_tags :: proc(p: ^Parser) -> (tags: ast.Proc_Tags) {
 		ident := expect_token(p, .Ident);
 		ident := expect_token(p, .Ident);
 
 
 		switch ident.text {
 		switch ident.text {
-		case "bounds_check":    tags |= {.Bounds_Check};
-		case "no_bounds_check": tags |= {.No_Bounds_Check};
-		case "optional_ok":     tags |= {.Optional_Ok};
-		case "optional_second": tags |= {.Optional_Second};
+		case "bounds_check":    tags += {.Bounds_Check};
+		case "no_bounds_check": tags += {.No_Bounds_Check};
+		case "optional_ok":     tags += {.Optional_Ok};
+		case "optional_second": tags += {.Optional_Second};
 		case:
 		case:
 		}
 		}
 	}
 	}
@@ -2267,12 +2267,12 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
 
 
 			switch name.text {
 			switch name.text {
 			case "bounds_check":
 			case "bounds_check":
-				operand.state_flags |= {.Bounds_Check};
+				operand.state_flags += {.Bounds_Check};
 				if .No_Bounds_Check in operand.state_flags {
 				if .No_Bounds_Check in operand.state_flags {
 					error(p, name.pos, "#bounds_check and #no_bounds_check cannot be applied together");
 					error(p, name.pos, "#bounds_check and #no_bounds_check cannot be applied together");
 				}
 				}
 			case "no_bounds_check":
 			case "no_bounds_check":
-				operand.state_flags |= {.No_Bounds_Check};
+				operand.state_flags += {.No_Bounds_Check};
 				if .Bounds_Check in operand.state_flags {
 				if .Bounds_Check in operand.state_flags {
 					error(p, name.pos, "#bounds_check and #no_bounds_check cannot be applied together");
 					error(p, name.pos, "#bounds_check and #no_bounds_check cannot be applied together");
 				}
 				}
@@ -3156,16 +3156,18 @@ parse_binary_expr :: proc(p: ^Parser, lhs: bool, prec_in: int) -> ^ast.Expr {
 	}
 	}
 
 
 	for prec := token_precedence(p, p.curr_tok.kind); prec >= prec_in; prec -= 1 {
 	for prec := token_precedence(p, p.curr_tok.kind); prec >= prec_in; prec -= 1 {
-		for {
+		loop: for {
 			op := p.curr_tok;
 			op := p.curr_tok;
 			op_prec := token_precedence(p, op.kind);
 			op_prec := token_precedence(p, op.kind);
 			if op_prec != prec {
 			if op_prec != prec {
-				break;
+				break loop;
 			}
 			}
-			if op.kind == .If || op.kind == .When {
+
+			#partial switch op.kind {
+			case .If, .When, .Or_Return, .Or_Else:
 				if p.prev_tok.pos.line < op.pos.line {
 				if p.prev_tok.pos.line < op.pos.line {
 					// NOTE(bill): Check to see if the `if` or `when` is on the same line of the `lhs` condition
 					// NOTE(bill): Check to see if the `if` or `when` is on the same line of the `lhs` condition
-					break;
+					break loop;
 				}
 				}
 			}
 			}
 
 
@@ -3178,7 +3180,7 @@ parse_binary_expr :: proc(p: ^Parser, lhs: bool, prec_in: int) -> ^ast.Expr {
 				x := parse_expr(p, lhs);
 				x := parse_expr(p, lhs);
 				colon := expect_token(p, .Colon);
 				colon := expect_token(p, .Colon);
 				y := parse_expr(p, lhs);
 				y := parse_expr(p, lhs);
-				te := ast.new(ast.Ternary_Expr, expr.pos, end_pos(p.prev_tok));
+				te := ast.new(ast.Ternary_If_Expr, expr.pos, end_pos(p.prev_tok));
 				te.cond = cond;
 				te.cond = cond;
 				te.op1  = op;
 				te.op1  = op;
 				te.x    = x;
 				te.x    = x;
@@ -3212,6 +3214,21 @@ parse_binary_expr :: proc(p: ^Parser, lhs: bool, prec_in: int) -> ^ast.Expr {
 				te.y    = y;
 				te.y    = y;
 
 
 				expr = te;
 				expr = te;
+			case .Or_Else:
+				x := expr;
+				y := parse_expr(p, lhs);
+				oe := ast.new(ast.Or_Else_Expr, expr.pos, end_pos(p.prev_tok));
+				oe.x     = x;
+				oe.token = op;
+				oe.y     = y;
+
+				expr = oe;
+			case .Or_Return:
+				oe := ast.new(ast.Or_Return_Expr, expr.pos, end_pos(p.prev_tok));
+				oe.expr  = expr;
+				oe.token = op;
+
+				expr = oe;
 			case:
 			case:
 				right := parse_binary_expr(p, false, prec+1);
 				right := parse_binary_expr(p, false, prec+1);
 				if right == nil {
 				if right == nil {

+ 7 - 6
core/odin/printer/visit.odin

@@ -944,12 +944,6 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
 	case Auto_Cast:
 	case Auto_Cast:
 		push_generic_token(p, v.op.kind, 1);
 		push_generic_token(p, v.op.kind, 1);
 		visit_expr(p, v.expr);
 		visit_expr(p, v.expr);
-	case Ternary_Expr:
-		visit_expr(p, v.cond);
-		push_generic_token(p, v.op1.kind, 1);
-		visit_expr(p, v.x);
-		push_generic_token(p, v.op2.kind, 1);
-		visit_expr(p, v.y);
 	case Ternary_If_Expr:
 	case Ternary_If_Expr:
 		visit_expr(p, v.x);
 		visit_expr(p, v.x);
 		push_generic_token(p, v.op1.kind, 1);
 		push_generic_token(p, v.op1.kind, 1);
@@ -962,6 +956,13 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
 		visit_expr(p, v.cond);
 		visit_expr(p, v.cond);
 		push_generic_token(p, v.op2.kind, 1);
 		push_generic_token(p, v.op2.kind, 1);
 		visit_expr(p, v.y);
 		visit_expr(p, v.y);
+	case Or_Else_Expr:
+		visit_expr(p, v.x);
+		push_generic_token(p, v.token.kind, 1);
+		visit_expr(p, v.y);
+	case Or_Return_Expr:
+		visit_expr(p, v.expr);
+		push_generic_token(p, v.token.kind, 1);
 	case Selector_Call_Expr:
 	case Selector_Call_Expr:
 		visit_expr(p, v.call.expr);
 		visit_expr(p, v.call.expr);
 		push_generic_token(p, .Open_Paren, 1);
 		push_generic_token(p, .Open_Paren, 1);

+ 8 - 4
core/odin/tokenizer/token.odin

@@ -144,10 +144,12 @@ Token_Kind :: enum u32 {
 		Transmute,   // transmute
 		Transmute,   // transmute
 		Distinct,    // distinct
 		Distinct,    // distinct
 		Using,       // using
 		Using,       // using
-		Inline,      // inline
-		No_Inline,   // no_inline
 		Context,     // context
 		Context,     // context
+		Or_Else,     // or_else
+		Or_Return,   // or_return
 		Asm,         // asm
 		Asm,         // asm
+		Inline,      // inline
+		No_Inline,   // no_inline
 	B_Keyword_End,
 	B_Keyword_End,
 
 
 	COUNT,
 	COUNT,
@@ -272,10 +274,12 @@ tokens := [Token_Kind.COUNT]string {
 	"transmute",
 	"transmute",
 	"distinct",
 	"distinct",
 	"using",
 	"using",
-	"inline",
-	"no_inline",
 	"context",
 	"context",
+	"or_else",
+	"or_return",
 	"asm",
 	"asm",
+	"inline",
+	"no_inline",
 	"",
 	"",
 };
 };
 
 

+ 1 - 1
core/odin/tokenizer/tokenizer.odin

@@ -724,7 +724,7 @@ scan :: proc(t: ^Tokenizer) -> Token {
 		case .Ident, .Context, .Typeid, .Break, .Continue, .Fallthrough, .Return,
 		case .Ident, .Context, .Typeid, .Break, .Continue, .Fallthrough, .Return,
 		     .Integer, .Float, .Imag, .Rune, .String, .Undef,
 		     .Integer, .Float, .Imag, .Rune, .String, .Undef,
 		     .Question, .Pointer, .Close_Paren, .Close_Bracket, .Close_Brace,
 		     .Question, .Pointer, .Close_Paren, .Close_Bracket, .Close_Brace,
-		     .Increment, .Decrement:
+		     .Increment, .Decrement, .Or_Return:
 			/*fallthrough*/
 			/*fallthrough*/
 			t.insert_semicolon = true;
 			t.insert_semicolon = true;
 		case:
 		case: