From 90d587df13c31e0c1c10d73287a3368df7cfad00 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 27 Oct 2021 23:49:37 +0100 Subject: [PATCH] Support `matrix` type in `core:odin` --- core/odin/ast/ast.odin | 17 +++++++++++ core/odin/ast/clone.odin | 9 +++++- core/odin/ast/walk.odin | 8 +++++ core/odin/parser/parser.odin | 56 ++++++++++++++++++++++++++-------- core/odin/tokenizer/token.odin | 14 +++++---- 5 files changed, 84 insertions(+), 20 deletions(-) diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index 2ed5c2b53..6de82c5d4 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -224,6 +224,15 @@ Slice_Expr :: struct { close: tokenizer.Pos, } +Matrix_Index_Expr :: struct { + using node: Expr, + expr: ^Expr, + open: tokenizer.Pos, + row_index: ^Expr, + column_index: ^Expr, + close: tokenizer.Pos, +} + Call_Expr :: struct { using node: Expr, inlining: Proc_Inlining, @@ -739,3 +748,11 @@ Relative_Type :: struct { tag: ^Expr, type: ^Expr, } + +Matrix_Type :: struct { + using node: Expr, + tok_pos: tokenizer.Pos, + row_count: ^Expr, + column_count: ^Expr, + elem: ^Expr, +} \ No newline at end of file diff --git a/core/odin/ast/clone.odin b/core/odin/ast/clone.odin index 143971a70..1e3058678 100644 --- a/core/odin/ast/clone.odin +++ b/core/odin/ast/clone.odin @@ -117,6 +117,10 @@ clone_node :: proc(node: ^Node) -> ^Node { case Index_Expr: r.expr = clone(r.expr) r.index = clone(r.index) + case Matrix_Index_Expr: + r.expr = clone(r.expr) + r.row_index = clone(r.row_index) + r.column_index = clone(r.column_index) case Deref_Expr: r.expr = clone(r.expr) case Slice_Expr: @@ -275,7 +279,10 @@ clone_node :: proc(node: ^Node) -> ^Node { case Map_Type: r.key = clone(r.key) r.value = clone(r.value) - + case Matrix_Type: + r.row_count = clone(r.row_count) + r.column_count = clone(r.column_count) + r.elem = clone(r.elem) case: fmt.panicf("Unhandled node kind: %T", r) } diff --git a/core/odin/ast/walk.odin b/core/odin/ast/walk.odin index f394a5e33..d0d17cc9e 100644 --- a/core/odin/ast/walk.odin +++ b/core/odin/ast/walk.odin @@ -110,6 +110,10 @@ walk :: proc(v: ^Visitor, node: ^Node) { case Index_Expr: walk(v, n.expr) walk(v, n.index) + case Matrix_Index_Expr: + walk(v, n.expr) + walk(v, n.row_index) + walk(v, n.column_index) case Deref_Expr: walk(v, n.expr) case Slice_Expr: @@ -398,6 +402,10 @@ walk :: proc(v: ^Visitor, node: ^Node) { case Relative_Type: walk(v, n.tag) walk(v, n.type) + case Matrix_Type: + walk(v, n.row_count) + walk(v, n.column_count) + walk(v, n.elem) case: fmt.panicf("ast.walk: unexpected node type %T", n) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index d6935c925..7660005e0 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -2703,6 +2703,22 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { bst.underlying = underlying bst.close = close.pos return bst + + case .Matrix: + tok := expect_token(p, .Matrix) + expect_token(p, .Open_Bracket) + row_count := parse_expr(p, false) + expect_token(p, .Comma) + column_count := parse_expr(p, false) + expect_token(p, .Close_Bracket) + elem := parse_type(p) + + mt := ast.new(ast.Matrix_Type, tok.pos, elem.end) + mt.tok_pos = tok.pos + mt.row_count = row_count + mt.column_count = column_count + mt.elem = elem + return mt case .Asm: tok := expect_token(p, .Asm) @@ -2969,7 +2985,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a defer p.allow_range = prev_allow_range p.allow_range = false - indicies: [2]^ast.Expr + indices: [2]^ast.Expr interval: tokenizer.Token is_slice_op := false @@ -2981,18 +2997,18 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a // NOTE(bill): Do not err yet break case: - indicies[0] = parse_expr(p, false) + indices[0] = parse_expr(p, false) } #partial switch p.curr_tok.kind { case .Ellipsis, .Range_Half, .Range_Full: error(p, p.curr_tok.pos, "expected a colon, not a range") fallthrough - case .Colon: + case .Colon, .Comma/*matrix index*/: interval = advance_token(p) is_slice_op = true if p.curr_tok.kind != .Close_Bracket && p.curr_tok.kind != .EOF { - indicies[1] = parse_expr(p, false) + indices[1] = parse_expr(p, false) } } @@ -3000,20 +3016,34 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a p.expr_level -= 1 if is_slice_op { - se := ast.new(ast.Slice_Expr, operand.pos, end_pos(close)) - se.expr = operand - se.open = open.pos - se.low = indicies[0] - se.interval = interval - se.high = indicies[1] - se.close = close.pos + if interval.kind == .Comma { + if indices[0] == nil || indices[1] == nil { + error(p, p.curr_tok.pos, "matrix index expressions require both row and column indices") + } + se := ast.new(ast.Matrix_Index_Expr, operand.pos, end_pos(close)) + se.expr = operand + se.open = open.pos + se.row_index = indices[0] + se.column_index = indices[1] + se.close = close.pos - operand = se + operand = se + } else { + se := ast.new(ast.Slice_Expr, operand.pos, end_pos(close)) + se.expr = operand + se.open = open.pos + se.low = indices[0] + se.interval = interval + se.high = indices[1] + se.close = close.pos + + operand = se + } } else { ie := ast.new(ast.Index_Expr, operand.pos, end_pos(close)) ie.expr = operand ie.open = open.pos - ie.index = indicies[0] + ie.index = indices[0] ie.close = close.pos operand = ie diff --git a/core/odin/tokenizer/token.odin b/core/odin/tokenizer/token.odin index 43a8552fa..35cb566be 100644 --- a/core/odin/tokenizer/token.odin +++ b/core/odin/tokenizer/token.odin @@ -150,6 +150,7 @@ Token_Kind :: enum u32 { Asm, // asm Inline, // inline No_Inline, // no_inline + Matrix, // matrix B_Keyword_End, COUNT, @@ -280,6 +281,7 @@ tokens := [Token_Kind.COUNT]string { "asm", "inline", "no_inline", + "matrix", "", } @@ -299,10 +301,10 @@ token_to_string :: proc(tok: Token) -> string { } to_string :: proc(kind: Token_Kind) -> string { - if Token_Kind.Invalid <= kind && kind < Token_Kind.COUNT { + if .Invalid <= kind && kind < .COUNT { return tokens[kind] } - if Token_Kind.B_Custom_Keyword_Begin < kind { + if .B_Custom_Keyword_Begin < kind { n := int(u16(kind)-u16(Token_Kind.B_Custom_Keyword_Begin)) if n < len(custom_keyword_tokens) { return custom_keyword_tokens[n] @@ -313,7 +315,7 @@ to_string :: proc(kind: Token_Kind) -> string { } is_literal :: proc(kind: Token_Kind) -> bool { - return Token_Kind.B_Literal_Begin < kind && kind < Token_Kind.B_Literal_End + return .B_Literal_Begin < kind && kind < .B_Literal_End } is_operator :: proc(kind: Token_Kind) -> bool { #partial switch kind { @@ -327,13 +329,13 @@ is_operator :: proc(kind: Token_Kind) -> bool { return false } is_assignment_operator :: proc(kind: Token_Kind) -> bool { - return Token_Kind.B_Assign_Op_Begin < kind && kind < Token_Kind.B_Assign_Op_End || kind == Token_Kind.Eq + return .B_Assign_Op_Begin < kind && kind < .B_Assign_Op_End || kind == .Eq } is_keyword :: proc(kind: Token_Kind) -> bool { switch { - case Token_Kind.B_Keyword_Begin < kind && kind < Token_Kind.B_Keyword_End: + case .B_Keyword_Begin < kind && kind < .B_Keyword_End: return true - case Token_Kind.B_Custom_Keyword_Begin < kind: + case .B_Custom_Keyword_Begin < kind: return true } return false