feat: execute fixed arrays and indexed access
This commit is contained in:
+91
-4
@@ -1,15 +1,15 @@
|
||||
#! grammar:
|
||||
#! * type ..... -> identifier
|
||||
#! * type ..... -> identifier | '[' (expr | '_') ']' ['mut'] type
|
||||
#! * binding ... -> :: | :=
|
||||
#! * literal .. -> int | float | string | 'true' | 'false'
|
||||
#! * op ....... -> '+' | '-' | '*' | '/' | '==' | '!=' | '<' | '<=' | '>' | '>=' | 'and' | 'or'
|
||||
#! * expr ..... -> identifier | literal | '(' expr ')' | ('-' | '!') expr | expr op expr | expr '(' [expr {',' expr} [',']] ')' | expr ('..' | '..=') expr
|
||||
#! * expr ..... -> identifier | literal | type | '[' [expr {',' expr} [',']] ']' | '(' expr ')' | ('-' | '!') expr | expr op expr | expr '(' [expr {',' expr} [',']] ')' | expr '[' expr ']' | expr ('..' | '..=') expr
|
||||
#! * decl ..... -> identifier [type] binding expr
|
||||
#! * block .... -> '{' {stmt} '}'
|
||||
#! * arm ...... -> block | stmt (single statements become canonical blocks)
|
||||
#! * stmt ..... -> decl | expr | identifier '=' expr | 'return' [expr] | 'break' | 'continue' | 'if' expr arm ['else' arm] | 'while' expr arm | 'for' expr '|' ['@'] identifier [',' identifier] '|' arm
|
||||
#! * stmt ..... -> decl | expr | expr '=' expr | 'return' [expr] | 'break' | 'continue' | 'if' expr arm ['else' arm] | 'while' expr arm | 'for' expr '|' ['@'] identifier [',' identifier] '|' arm
|
||||
#! braceless guards/iterables require parentheses unless they are calls; else binds to the nearest if.
|
||||
#! precedence (tightest first): calls, unary -/!, multiplication/division, addition/subtraction, relational comparisons, equality, and, or, ranges. compound range endpoints require their own parentheses.
|
||||
#! precedence (tightest first): calls/indices, unary -/!, multiplication/division, addition/subtraction, relational comparisons, equality, and, or, ranges. compound range endpoints require their own parentheses.
|
||||
#! binary operators associate left; unary operators associate right.
|
||||
|
||||
import "@std/debug"
|
||||
@@ -40,6 +40,9 @@ ExprKind :: enum {
|
||||
binary
|
||||
call
|
||||
range
|
||||
array_type
|
||||
array_literal
|
||||
index
|
||||
invalid
|
||||
}
|
||||
|
||||
@@ -86,6 +89,9 @@ NodeKind :: enum {
|
||||
expr_binary,
|
||||
expr_call,
|
||||
expr_range,
|
||||
expr_array_type,
|
||||
expr_array_literal,
|
||||
expr_index,
|
||||
stmt_expr,
|
||||
stmt_decl,
|
||||
stmt_return,
|
||||
@@ -181,6 +187,19 @@ CallExprView :: struct {
|
||||
callee NodeId
|
||||
}
|
||||
|
||||
ArrayTypeView :: struct {
|
||||
span Span
|
||||
count ?NodeId
|
||||
element NodeId
|
||||
mutable bool
|
||||
}
|
||||
|
||||
IndexView :: struct {
|
||||
span Span
|
||||
base NodeId
|
||||
index NodeId
|
||||
}
|
||||
|
||||
ReturnView :: struct {
|
||||
span Span
|
||||
value ?NodeId
|
||||
@@ -336,6 +355,37 @@ add_call proc(
|
||||
}, span)
|
||||
}
|
||||
|
||||
add_array_type proc(
|
||||
builder @mut Builder, span Span, count ?NodeId, element NodeId, mutable bool,
|
||||
) NodeId ! mem.AllocError {
|
||||
raw_count :: if (count) |id| id else no_node
|
||||
flag :: if (mutable) u32(1) else u32(0)
|
||||
return try add_node(builder, Node{
|
||||
kind = .expr_array_type,
|
||||
main = NodeData{ extra = flag },
|
||||
data0 = NodeData{ node_id = raw_count },
|
||||
data1 = NodeData{ node_id = element },
|
||||
}, span)
|
||||
}
|
||||
|
||||
add_array_literal proc(builder @mut Builder, span Span, elements []NodeId) NodeId ! mem.AllocError {
|
||||
start :: builder.storage.extra.items.len
|
||||
for (elements) |element| _ = try add_extra(builder, u32(element))
|
||||
return try add_node(builder, Node{
|
||||
kind = .expr_array_literal,
|
||||
data0 = NodeData{ extra = u32(start) },
|
||||
data1 = NodeData{ extra = u32(builder.storage.extra.items.len) },
|
||||
}, span)
|
||||
}
|
||||
|
||||
add_index proc(builder @mut Builder, span Span, base, index NodeId) NodeId ! mem.AllocError {
|
||||
return try add_node(builder, Node{
|
||||
kind = .expr_index,
|
||||
data0 = NodeData{ node_id = base },
|
||||
data1 = NodeData{ node_id = index },
|
||||
}, span)
|
||||
}
|
||||
|
||||
add_expression_stmt proc(builder @mut Builder, expression NodeId) NodeId ! mem.AllocError {
|
||||
return try add_node(builder, Node{
|
||||
kind = .stmt_expr,
|
||||
@@ -710,6 +760,9 @@ expression_kind proc(kind NodeKind) ExprKind {
|
||||
.expr_binary: .binary
|
||||
.expr_call: .call
|
||||
.expr_range: .range
|
||||
.expr_array_type: .array_type
|
||||
.expr_array_literal: .array_literal
|
||||
.expr_index: .index
|
||||
.invalid_expr: .invalid
|
||||
else: unreachable
|
||||
}
|
||||
@@ -769,6 +822,40 @@ call_arg proc(tree @Tree, id NodeId, index usize) NodeId {
|
||||
return NodeId(tree.storage.extra.items[usize(node.data0.extra) + index])
|
||||
}
|
||||
|
||||
array_type proc(tree @Tree, id NodeId) ArrayTypeView {
|
||||
node :: get_node(&tree.storage, id)
|
||||
debug.assert(node.kind == .expr_array_type)
|
||||
return ArrayTypeView{
|
||||
span = get_span(&tree.storage, id),
|
||||
count = maybe_node_id(u32(node.data0.node_id)),
|
||||
element = node.data1.node_id,
|
||||
mutable = node.main.extra != 0,
|
||||
}
|
||||
}
|
||||
|
||||
array_element_count proc(tree @Tree, id NodeId) usize {
|
||||
node :: get_node(&tree.storage, id)
|
||||
debug.assert(node.kind == .expr_array_literal)
|
||||
return usize(node.data1.extra - node.data0.extra)
|
||||
}
|
||||
|
||||
array_element proc(tree @Tree, id NodeId, index usize) NodeId {
|
||||
node :: get_node(&tree.storage, id)
|
||||
debug.assert(node.kind == .expr_array_literal)
|
||||
debug.assert(index < usize(node.data1.extra - node.data0.extra))
|
||||
return NodeId(tree.storage.extra.items[usize(node.data0.extra) + index])
|
||||
}
|
||||
|
||||
index_expr proc(tree @Tree, id NodeId) IndexView {
|
||||
node :: get_node(&tree.storage, id)
|
||||
debug.assert(node.kind == .expr_index)
|
||||
return IndexView{
|
||||
span = get_span(&tree.storage, id),
|
||||
base = node.data0.node_id,
|
||||
index = node.data1.node_id,
|
||||
}
|
||||
}
|
||||
|
||||
node_span proc(tree @Tree, id NodeId) Span {
|
||||
return get_span(&tree.storage, id)
|
||||
}
|
||||
|
||||
@@ -32,3 +32,35 @@ exposes_typed_declaration_views test {
|
||||
try testing.expect_equal(ExprKind.literal_int, expr_kind(&tree, statement.initializer))
|
||||
try testing.expect_equal("value", source_text(&tree, statement.name))
|
||||
}
|
||||
|
||||
exposes_array_type_literal_and_index_views test {
|
||||
builder := init_builder(mem.c_allocator, "")
|
||||
defer deinit_builder(&builder)
|
||||
span :: Span{ start = 0, end = 0 }
|
||||
count :: try add_literal(&builder, .int, span)
|
||||
element :: try add_identifier(&builder, span)
|
||||
row :: try add_array_type(&builder, span, count, element, false)
|
||||
matrix :: try add_array_type(&builder, span, null, row, true)
|
||||
elements [2]NodeId :: [count, element]
|
||||
literal :: try add_array_literal(&builder, span, elements[..])
|
||||
empty :: try add_array_literal(&builder, span, &[])
|
||||
indexed :: try add_index(&builder, span, literal, count)
|
||||
package :: try add_package(&builder, span, &[])
|
||||
tree := finish(&builder, package)
|
||||
defer deinit(&tree)
|
||||
try testing.expect_equal(ExprKind.array_type, expr_kind(&tree, matrix))
|
||||
try testing.expect_equal(null, array_type(&tree, matrix).count)
|
||||
try testing.expect(array_type(&tree, matrix).mutable)
|
||||
try testing.expect_equal(row, array_type(&tree, matrix).element)
|
||||
try testing.expect_equal(count, array_type(&tree, row).count?)
|
||||
try testing.expect(!array_type(&tree, row).mutable)
|
||||
try testing.expect_equal(element, array_type(&tree, row).element)
|
||||
try testing.expect_equal(ExprKind.array_literal, expr_kind(&tree, literal))
|
||||
try testing.expect_equal(2, array_element_count(&tree, literal))
|
||||
try testing.expect_equal(count, array_element(&tree, literal, 0))
|
||||
try testing.expect_equal(element, array_element(&tree, literal, 1))
|
||||
try testing.expect_equal(0, array_element_count(&tree, empty))
|
||||
try testing.expect_equal(ExprKind.index, expr_kind(&tree, indexed))
|
||||
try testing.expect_equal(literal, index_expr(&tree, indexed).base)
|
||||
try testing.expect_equal(count, index_expr(&tree, indexed).index)
|
||||
}
|
||||
|
||||
@@ -132,6 +132,12 @@ render_statement proc(
|
||||
try append_text(renderer, indent)
|
||||
try append_text(renderer, "declaration ")
|
||||
try append_text(renderer, ast.source_text(tree, statement.name))
|
||||
if (statement.type) |type| {
|
||||
try append_text(renderer, " ")
|
||||
try append_text(renderer, ast.source_text(tree, ast.node_span(tree, type)))
|
||||
}
|
||||
try append_text(renderer, if (statement.mutability == .constant) " :: " else " := ")
|
||||
try append_text(renderer, ast.source_text(tree, ast.node_span(tree, statement.initializer)))
|
||||
try append_text(renderer, "\n")
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import "@std/mem"
|
||||
import "@std/testing"
|
||||
import "@source/diagnostics"
|
||||
import "@source/strpool"
|
||||
import "@source/lexer"
|
||||
import "@source/parser"
|
||||
import "@source/ast"
|
||||
|
||||
renders_array_annotations_literals_and_indexed_assignments test {
|
||||
strpool.strings = strpool.init(mem.c_allocator)
|
||||
defer strpool.deinit(&strpool.strings)
|
||||
diagnostic_store := diagnostics.init(mem.c_allocator)
|
||||
defer diagnostics.deinit(&diagnostic_store)
|
||||
source ::
|
||||
`data [2]mut i64 := [1, 2]
|
||||
`main proc() i64 {
|
||||
` (data)[0] = 9
|
||||
` return data[0]
|
||||
`}
|
||||
scan_state := lexer.init(mem.c_allocator)
|
||||
defer lexer.deinit(&scan_state)
|
||||
try lexer.scan(&scan_state, source, &diagnostic_store)
|
||||
tree := try parser.parse(mem.c_allocator, scan_state.tokens.items, source, &diagnostic_store)
|
||||
defer ast.deinit(&tree)
|
||||
renderer := init(mem.c_allocator)
|
||||
defer deinit(&renderer)
|
||||
try render(&renderer, &tree)
|
||||
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
||||
try testing.expect_equal(
|
||||
"package\n declaration data [2]mut i64 := [1, 2]\n function main\n assignment (data)[0] = 9\n return data[0]\n",
|
||||
renderer.bytes.items,
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user