Skip to content

Commit bc1a7f6

Browse files
on-keydayclaude
andcommitted
ast: let a path end at a vector
A vector segment had to be followed by an index, so there was no way to ask for the vector to iterate it. Ending the path there now yields a pointer to it, the same shape a scalar already gave. fmt.field<"body.elements">() // std::vector<Node<Statement>>* fmt.field<"body.elements.0">() // Ref<Statement> .optional on a vector is rejected rather than supported: it would return the vector by value, and whether the path resolved is already answered by the pointer. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 40a3c15 commit bc1a7f6

3 files changed

Lines changed: 30 additions & 1 deletion

File tree

src/core/nast/access.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// auto body = fmt.field<"body">(); // Ref<Body> (Ref は arena を持つ)
1010
// auto st = fmt.field<"body.struct_type">(); // Ref<StructType>
1111
// auto f0 = fmt.field<"body.elements.0">(); // Ref<Statement>
12+
// auto all = fmt.field<"body.elements">(); // std::vector<Node<Statement>>*
1213
// auto name = fmt.field<"name.identifier">(); // std::string*
1314
// auto st2 = node.field<"body.struct_type">(arena); // Node は arena を渡す
1415
// auto id = fmt.field<"name.identifier.optional">(); // std::optional<std::string>
@@ -139,11 +140,21 @@ namespace brgen::nast {
139140
return walk<Rest, U>(a, a.template get<U>(member));
140141
}
141142
}
143+
else if constexpr (vec::is_vector && is_empty<Rest>()) {
144+
// 配列そのもの。スカラーと同じくポインタで返す (回すのに要る)。
145+
return &member;
146+
}
147+
else if constexpr (vec::is_vector && is_optional_marker<Rest>()) {
148+
// 値で返すと配列を複製することになる。null かどうかは
149+
// ポインタ形で判定できるので、そちらを使わせる。
150+
static_assert(!is_optional_marker<Rest>(),
151+
"a vector cannot take .optional; drop it and check the pointer");
152+
}
142153
else if constexpr (vec::is_vector) {
143154
using U = typename vec::type;
144155
constexpr auto idx_seg = head<Rest>();
145156
static_assert(all_digit(idx_seg.view()),
146-
"a vector field must be followed by an array index");
157+
"a vector field must be followed by an array index, or end the path here");
147158
constexpr auto i = to_index<idx_seg>();
148159
constexpr auto after = tail<Rest>();
149160
if (member.size() <= i) {

src/core/nast/bind/binder.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*license*/
2+
#pragma once
3+
#include "../nodes.h"
4+
#include "../access.h"
5+
6+
namespace brgen::nast::bind {
7+
struct Binder {
8+
Arena& a;
9+
10+
void bind(Node<Module> mod) {
11+
for (auto& bound : mod.ref(a)->statements) {
12+
}
13+
}
14+
};
15+
} // namespace brgen::nast::bind

src/core/nast/test.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,9 @@ int main(int argc, char** argv) {
241241
"field<> follows Node fields through the arena, from Ref and from Node");
242242
check(f.field<"body.elements.0">().id() == fld.id(),
243243
"field<> indexes into a vector field");
244+
auto* elems = f.field<"body.elements">();
245+
check(elems && elems->size() == 1 && (*elems)[0] == fld.id(),
246+
"ending the path at a vector gives the vector itself");
244247
check(!f.field<"body.elements.9">(),
245248
"out of range index yields a null ref, not a crash");
246249
auto* ident = f.field<"name.identifier">();

0 commit comments

Comments
 (0)