Skip to content

Commit 4225f0c

Browse files
authored
Merge pull request #2826 from ruby/flat-locations
Delete global constant pool from the parser
2 parents e85bb1f + 7595e20 commit 4225f0c

File tree

22 files changed

+2534
-1337
lines changed

22 files changed

+2534
-1337
lines changed

config.yml

Lines changed: 213 additions & 44 deletions
Large diffs are not rendered by default.

docs/config.md

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
# config.yml
2+
3+
`config.yml` is the definition of data structure for parser results -- AST.
4+
5+
It defines the data structure for the parser implementation in C and Rust `node` modules.
6+
7+
## C parser code
8+
9+
```sh
10+
$ rake templates
11+
```
12+
13+
Our C parser consists of two components:
14+
15+
1. Pure C Parser
16+
2. Translator from the pure C AST to Ruby object
17+
18+
`config.yml` defines the AST for pure C parser in `ast.h`/`ast.c` and translator from the C AST to Ruby objects in `ast_translation.h`/`ast_translation.c`.
19+
20+
## `ruby-rbs` crate
21+
22+
```sh
23+
$ cd rust; cargo build
24+
```
25+
26+
The `build.rs` in `ruby-rbs` crate defines the data structure derived from `config.yml` definitions under `node` module.
27+
28+
## nodes
29+
30+
`nodes` defines *node* data types in C or Rust.
31+
32+
```yaml
33+
nodes:
34+
- name: RBS::AST::Declarations::Class
35+
rust_name: ClassNode
36+
fields:
37+
- name: name
38+
c_type: rbs_type_name
39+
- name: type_params
40+
c_type: rbs_node_list
41+
- name: super_class
42+
c_type: rbs_ast_declarations_class_super
43+
optional: true # NULL when no superclass (e.g., `class Foo end` vs `class Foo < Bar end`)
44+
- name: members
45+
c_type: rbs_node_list
46+
- name: annotations
47+
c_type: rbs_node_list
48+
- name: comment
49+
c_type: rbs_ast_comment
50+
optional: true # NULL when no comment precedes the declaration
51+
```
52+
53+
This defines `rbs_ast_declarations_class` struct so that the parser constructs the AST using the structs.
54+
55+
```c
56+
typedef struct rbs_ast_declarations_class {
57+
rbs_node_t base;
58+
59+
struct rbs_type_name *name;
60+
struct rbs_node_list *type_params;
61+
struct rbs_ast_declarations_class_super *super_class; /* Optional */
62+
struct rbs_node_list *members;
63+
struct rbs_node_list *annotations;
64+
struct rbs_ast_comment *comment; /* Optional */
65+
66+
rbs_location_range keyword_range; /* Required */
67+
rbs_location_range name_range; /* Required */
68+
rbs_location_range end_range; /* Required */
69+
rbs_location_range type_params_range; /* Optional */
70+
rbs_location_range lt_range; /* Optional */
71+
} rbs_ast_declarations_class_t;
72+
```
73+
74+
The `rbs_ast_declarations_class` struct is a pure C AST, and `ast_translation.c` defines translation into a Ruby object of `RBS::AST::Declarations::Class` class.
75+
76+
```c
77+
case RBS_AST_DECLARATIONS_CLASS: {
78+
rbs_ast_declarations_class_t *node = (rbs_ast_declarations_class_t *) instance;
79+
80+
VALUE h = rb_hash_new();
81+
VALUE location = rbs_location_range_to_ruby_location(ctx, node->base.location);
82+
rbs_loc *loc = rbs_check_location(location);
83+
rbs_loc_legacy_alloc_children(loc, 5);
84+
rbs_loc_legacy_add_required_child(loc, rb_intern("keyword"), (rbs_loc_range) { .start = node->keyword_range.start_char, .end = node->keyword_range.end_char });
85+
rbs_loc_legacy_add_required_child(loc, rb_intern("name"), (rbs_loc_range) { .start = node->name_range.start_char, .end = node->name_range.end_char });
86+
rbs_loc_legacy_add_required_child(loc, rb_intern("end"), (rbs_loc_range) { .start = node->end_range.start_char, .end = node->end_range.end_char });
87+
rbs_loc_legacy_add_optional_child(loc, rb_intern("type_params"), (rbs_loc_range) { .start = node->type_params_range.start_char, .end = node->type_params_range.end_char });
88+
rbs_loc_legacy_add_optional_child(loc, rb_intern("lt"), (rbs_loc_range) { .start = node->lt_range.start_char, .end = node->lt_range.end_char });
89+
rb_hash_aset(h, ID2SYM(rb_intern("location")), location);
90+
rb_hash_aset(h, ID2SYM(rb_intern("name")), rbs_struct_to_ruby_value(ctx, (rbs_node_t *) node->name)); // rbs_type_name
91+
rb_hash_aset(h, ID2SYM(rb_intern("type_params")), rbs_node_list_to_ruby_array(ctx, node->type_params));
92+
rb_hash_aset(h, ID2SYM(rb_intern("super_class")), rbs_struct_to_ruby_value(ctx, (rbs_node_t *) node->super_class)); // rbs_ast_declarations_class_super
93+
rb_hash_aset(h, ID2SYM(rb_intern("members")), rbs_node_list_to_ruby_array(ctx, node->members));
94+
rb_hash_aset(h, ID2SYM(rb_intern("annotations")), rbs_node_list_to_ruby_array(ctx, node->annotations));
95+
rb_hash_aset(h, ID2SYM(rb_intern("comment")), rbs_struct_to_ruby_value(ctx, (rbs_node_t *) node->comment)); // rbs_ast_comment
96+
97+
rb_funcall(
98+
RBS_AST_TypeParam,
99+
rb_intern("resolve_variables"),
100+
1,
101+
rb_hash_lookup(h, ID2SYM(rb_intern("type_params")))
102+
);
103+
return CLASS_NEW_INSTANCE(
104+
RBS_AST_Declarations_Class,
105+
1,
106+
&h
107+
);
108+
}
109+
```
110+
111+
## enums
112+
113+
`enums` defines *enum* data types in C or Rust.
114+
115+
```yaml
116+
enums:
117+
attribute_visibility:
118+
optional: true
119+
symbols:
120+
- unspecified
121+
- public
122+
- private
123+
```
124+
125+
For example, the `attribute_visibility` enum is a data type for `visibility` attribute of `attr_reader`, `attr_writer`, and `attr_accessor` definitions.
126+
The `visibility` attribute can be one of `unspecified`, `public`, and `private`.
127+
128+
### Symbol enums
129+
130+
Enum definition with `symbols:` attribute defines *enum* data that is mapped to Ruby symbols.
131+
132+
```yaml
133+
enums:
134+
attribute_visibility:
135+
optional: true
136+
symbols:
137+
- unspecified
138+
- public
139+
- private
140+
```
141+
142+
It defines an `enum` in C AST definition.
143+
144+
```c
145+
enum RBS_ATTRIBUTE_VISIBILITY_TAG {
146+
RBS_ATTRIBUTE_VISIBILITY_TAG_UNSPECIFIED,
147+
RBS_ATTRIBUTE_VISIBILITY_TAG_PUBLIC,
148+
RBS_ATTRIBUTE_VISIBILITY_TAG_PRIVATE,
149+
};
150+
```
151+
152+
The C extension also defines a translation:
153+
154+
```c
155+
VALUE rbs_attribute_visibility_to_ruby(enum rbs_attribute_visibility value) {
156+
switch (value) {
157+
case RBS_ATTRIBUTE_VISIBILITY_UNSPECIFIED:
158+
return Qnil;
159+
case RBS_ATTRIBUTE_VISIBILITY_PUBLIC:
160+
return rb_id2sym(rb_intern("public"));
161+
case RBS_ATTRIBUTE_VISIBILITY_PRIVATE:
162+
return rb_id2sym(rb_intern("private"));
163+
default:
164+
rb_fatal("unknown enum rbs_attribute_visibility value: %d", value);
165+
}
166+
}
167+
```
168+
169+
`RBS_ATTRIBUTE_VISIBILITY_PUBLIC` and `RBS_ATTRIBUTE_VISIBILITY_PRIVATE` are translated to Ruby symbols `:public` and `:private` respectively.
170+
171+
Note that the first `RBS_ATTRIBUTE_VISIBILITY_UNSPECIFIED` is translated to `nil` in Ruby. This is specified by the `optional: true` attribute in YAML. When `optional: true` is set, the first enum value is translated to `nil`.

0 commit comments

Comments
 (0)