Ruby 4.1.0dev (2026-08-14 revision 7da70f17736d9a210167dda5636e76183136bb43)
node.c (7da70f17736d9a210167dda5636e76183136bb43)
1/**********************************************************************
2
3 node.c - ruby node tree
4
5 $Author: mame $
6 created at: 09/12/06 21:23:44 JST
7
8 Copyright (C) 2009 Yusuke Endoh
9
10**********************************************************************/
11
12#ifdef UNIVERSAL_PARSER
13#include <stddef.h>
14#include "rubyparser.h"
15#endif
16
17#include "internal.h"
18#include "internal/variable.h"
19#include "node.h"
20
21#define NODE_BUF_DEFAULT_SIZE (sizeof(struct RNode) * 16)
22
23static void
24init_node_buffer_elem(node_buffer_elem_t *nbe, size_t allocated, void *xmalloc(size_t))
25{
26 nbe->allocated = allocated;
27 nbe->used = 0;
28 nbe->len = 0;
29 nbe->nodes = xmalloc(allocated / sizeof(struct RNode) * sizeof(struct RNode *)); /* All node requires at least RNode */
30}
31
32static void
33init_node_buffer_list(node_buffer_list_t *nb, node_buffer_elem_t *head, void *xmalloc(size_t))
34{
35 init_node_buffer_elem(head, NODE_BUF_DEFAULT_SIZE, xmalloc);
36 nb->head = nb->last = head;
37 nb->head->next = NULL;
38}
39
40#ifdef UNIVERSAL_PARSER
41#define ruby_xmalloc config->malloc
42#endif
43
44#ifdef UNIVERSAL_PARSER
45static node_buffer_t *
46rb_node_buffer_new(const rb_parser_config_t *config)
47#else
48static node_buffer_t *
49rb_node_buffer_new(void)
50#endif
51{
52 const size_t bucket_size = offsetof(node_buffer_elem_t, buf) + NODE_BUF_DEFAULT_SIZE;
53 const size_t alloc_size = sizeof(node_buffer_t) + (bucket_size);
54 STATIC_ASSERT(
55 integer_overflow,
56 offsetof(node_buffer_elem_t, buf) + NODE_BUF_DEFAULT_SIZE
57 > sizeof(node_buffer_t) + sizeof(node_buffer_elem_t));
58 node_buffer_t *nb = ruby_xmalloc(alloc_size);
59 init_node_buffer_list(&nb->buffer_list, (node_buffer_elem_t*)&nb[1], ruby_xmalloc);
60 nb->local_tables = 0;
61 nb->tokens = 0;
62 return nb;
63}
64
65#ifdef UNIVERSAL_PARSER
66#undef ruby_xmalloc
67#define ruby_xmalloc ast->config->malloc
68#undef xfree
69#define xfree ast->config->free
70#define rb_xmalloc_mul_add ast->config->xmalloc_mul_add
71#define ruby_xrealloc(var,size) (ast->config->realloc_n((void *)var, 1, size))
72#endif
73
74typedef void node_itr_t(rb_ast_t *ast, void *ctx, NODE *node);
75static void iterate_node_values(rb_ast_t *ast, node_buffer_list_t *nb, node_itr_t * func, void *ctx);
76
77void
78rb_node_init(NODE *n, enum node_type type)
79{
80 RNODE(n)->flags = 0;
81 nd_init_type(RNODE(n), type);
82 RNODE(n)->nd_loc.beg_pos.lineno = 0;
83 RNODE(n)->nd_loc.beg_pos.column = 0;
84 RNODE(n)->nd_loc.end_pos.lineno = 0;
85 RNODE(n)->nd_loc.end_pos.column = 0;
86 RNODE(n)->node_id = -1;
87}
88
89const char *
90rb_node_name(int node)
91{
92 switch (node) {
93#include "node_name.inc"
94 default:
95 return 0;
96 }
97}
98
99#ifdef UNIVERSAL_PARSER
100const char *
101ruby_node_name(int node)
102{
103 return rb_node_name(node);
104}
105#else
106const char *
107ruby_node_name(int node)
108{
109 const char *name = rb_node_name(node);
110
111 if (!name) rb_bug("unknown node: %d", node);
112 return name;
113}
114#endif
115
116static void
117node_buffer_list_free(rb_ast_t *ast, node_buffer_list_t * nb)
118{
119 node_buffer_elem_t *nbe = nb->head;
120 while (nbe != nb->last) {
121 void *buf = nbe;
122 xfree(nbe->nodes);
123 nbe = nbe->next;
124 xfree(buf);
125 }
126
127 /* The last node_buffer_elem_t is allocated in the node_buffer_t, so we
128 * only need to free the nodes. */
129 xfree(nbe->nodes);
130}
131
133 struct rb_ast_local_table_link *next;
134 // struct rb_ast_id_table {
135 int size;
136 ID ids[FLEX_ARY_LEN];
137 // }
138};
139
140static void
141parser_string_free(rb_ast_t *ast, rb_parser_string_t *str)
142{
143 if (!str) return;
144 xfree(str->ptr);
145 xfree(str);
146}
147
148static void
149parser_ast_token_free(rb_ast_t *ast, rb_parser_ast_token_t *token)
150{
151 if (!token) return;
152 parser_string_free(ast, token->str);
153 xfree(token);
154}
155
156static void
157parser_tokens_free(rb_ast_t *ast, rb_parser_ary_t *tokens)
158{
159 for (long i = 0; i < tokens->len; i++) {
160 parser_ast_token_free(ast, tokens->data[i]);
161 }
162 xfree(tokens->data);
163 xfree(tokens);
164}
165
166static void
167parser_nodes_free(rb_ast_t *ast, rb_parser_ary_t *nodes)
168{
169 /* Do nothing for nodes because nodes are freed when rb_ast_t is freed */
170 xfree(nodes->data);
171 xfree(nodes);
172}
173
174static void
175free_ast_value(rb_ast_t *ast, void *ctx, NODE *node)
176{
177 switch (nd_type(node)) {
178 case NODE_STR:
179 parser_string_free(ast, RNODE_STR(node)->string);
180 break;
181 case NODE_DSTR:
182 parser_string_free(ast, RNODE_DSTR(node)->string);
183 break;
184 case NODE_XSTR:
185 parser_string_free(ast, RNODE_XSTR(node)->string);
186 break;
187 case NODE_DXSTR:
188 parser_string_free(ast, RNODE_DXSTR(node)->string);
189 break;
190 case NODE_SYM:
191 parser_string_free(ast, RNODE_SYM(node)->string);
192 break;
193 case NODE_REGX:
194 case NODE_MATCH:
195 parser_string_free(ast, RNODE_REGX(node)->string);
196 break;
197 case NODE_DSYM:
198 parser_string_free(ast, RNODE_DSYM(node)->string);
199 break;
200 case NODE_DREGX:
201 parser_string_free(ast, RNODE_DREGX(node)->string);
202 break;
203 case NODE_FILE:
204 parser_string_free(ast, RNODE_FILE(node)->path);
205 break;
206 case NODE_INTEGER:
207 xfree(RNODE_INTEGER(node)->val);
208 break;
209 case NODE_FLOAT:
210 xfree(RNODE_FLOAT(node)->val);
211 break;
212 case NODE_RATIONAL:
213 xfree(RNODE_RATIONAL(node)->val);
214 break;
215 case NODE_IMAGINARY:
216 xfree(RNODE_IMAGINARY(node)->val);
217 break;
218 case NODE_UNDEF:
219 parser_nodes_free(ast, RNODE_UNDEF(node)->nd_undefs);
220 break;
221 default:
222 break;
223 }
224}
225
226static void
227rb_node_buffer_free(rb_ast_t *ast, node_buffer_t *nb)
228{
229 if (nb->tokens) {
230 parser_tokens_free(ast, nb->tokens);
231 }
232 iterate_node_values(ast, &nb->buffer_list, free_ast_value, NULL);
233 node_buffer_list_free(ast, &nb->buffer_list);
234 struct rb_ast_local_table_link *local_table = nb->local_tables;
235 while (local_table) {
236 struct rb_ast_local_table_link *next_table = local_table->next;
237 xfree(local_table);
238 local_table = next_table;
239 }
240 xfree(nb);
241}
242
243#define buf_add_offset(nbe, offset) ((char *)(nbe->buf) + (offset))
244
245static NODE *
246ast_newnode_in_bucket(rb_ast_t *ast, node_buffer_list_t *nb, size_t size, size_t alignment)
247{
248 size_t padding;
249 NODE *ptr;
250
251 padding = alignment - (size_t)buf_add_offset(nb->head, nb->head->used) % alignment;
252 padding = padding == alignment ? 0 : padding;
253
254 if (nb->head->used + size + padding > nb->head->allocated) {
255 size_t n = nb->head->allocated * 2;
256 node_buffer_elem_t *nbe;
257 nbe = rb_xmalloc_mul_add(n, sizeof(char *), offsetof(node_buffer_elem_t, buf));
258 init_node_buffer_elem(nbe, n, ruby_xmalloc);
259 nbe->next = nb->head;
260 nb->head = nbe;
261 padding = 0; /* malloc returns aligned address then no need to add padding */
262 }
263
264 ptr = (NODE *)buf_add_offset(nb->head, nb->head->used + padding);
265 nb->head->used += (size + padding);
266 nb->head->nodes[nb->head->len++] = ptr;
267 return ptr;
268}
269
270NODE *
271rb_ast_newnode(rb_ast_t *ast, enum node_type type, size_t size, size_t alignment)
272{
273 node_buffer_t *nb = ast->node_buffer;
274 node_buffer_list_t *bucket = &nb->buffer_list;
275 return ast_newnode_in_bucket(ast, bucket, size, alignment);
276}
277
279rb_ast_new_local_table(rb_ast_t *ast, int size)
280{
281 size_t alloc_size = sizeof(struct rb_ast_local_table_link) + size * sizeof(ID);
282 struct rb_ast_local_table_link *link = ruby_xmalloc(alloc_size);
283 link->next = ast->node_buffer->local_tables;
284 ast->node_buffer->local_tables = link;
285 link->size = size;
286
287 return (rb_ast_id_table_t *) &link->size;
288}
289
291rb_ast_resize_latest_local_table(rb_ast_t *ast, int size)
292{
293 struct rb_ast_local_table_link *link = ast->node_buffer->local_tables;
294 size_t alloc_size = sizeof(struct rb_ast_local_table_link) + size * sizeof(ID);
295 link = ruby_xrealloc(link, alloc_size);
296 ast->node_buffer->local_tables = link;
297 link->size = size;
298
299 return (rb_ast_id_table_t *) &link->size;
300}
301
302void
303rb_ast_delete_node(rb_ast_t *ast, NODE *n)
304{
305 (void)ast;
306 (void)n;
307 /* should we implement freelist? */
308}
309
310#ifdef UNIVERSAL_PARSER
311rb_ast_t *
312rb_ast_new(const rb_parser_config_t *config)
313{
314 node_buffer_t *nb = rb_node_buffer_new(config);
315 rb_ast_t *ast = (rb_ast_t *)config->calloc(1, sizeof(rb_ast_t));
316 ast->config = config;
317 ast->node_buffer = nb;
318 return ast;
319}
320#else
321rb_ast_t *
322rb_ast_new(void)
323{
324 node_buffer_t *nb = rb_node_buffer_new();
325 rb_ast_t *ast = ruby_xcalloc(1, sizeof(rb_ast_t));
326 ast->node_buffer = nb;
327 return ast;
328}
329#endif
330
331static void
332iterate_buffer_elements(rb_ast_t *ast, node_buffer_elem_t *nbe, long len, node_itr_t *func, void *ctx)
333{
334 long cursor;
335 for (cursor = 0; cursor < len; cursor++) {
336 func(ast, ctx, nbe->nodes[cursor]);
337 }
338}
339
340static void
341iterate_node_values(rb_ast_t *ast, node_buffer_list_t *nb, node_itr_t * func, void *ctx)
342{
343 node_buffer_elem_t *nbe = nb->head;
344
345 while (nbe) {
346 iterate_buffer_elements(ast, nbe, nbe->len, func, ctx);
347 nbe = nbe->next;
348 }
349}
350
351static void
352script_lines_free(rb_ast_t *ast, rb_parser_ary_t *script_lines)
353{
354 if (!script_lines) return;
355 for (long i = 0; i < script_lines->len; i++) {
356 parser_string_free(ast, (rb_parser_string_t *)script_lines->data[i]);
357 }
358 xfree(script_lines->data);
359 xfree(script_lines);
360}
361
362void
363rb_ast_free(rb_ast_t *ast)
364{
365 rb_ast_dispose(ast);
366 xfree(ast);
367}
368
369static size_t
370buffer_list_size(node_buffer_list_t *nb)
371{
372 size_t size = 0;
373 node_buffer_elem_t *nbe = nb->head;
374 while (nbe != nb->last) {
375 size += offsetof(node_buffer_elem_t, buf) + nbe->used;
376 nbe = nbe->next;
377 }
378 return size;
379}
380
381size_t
382rb_ast_memsize(const rb_ast_t *ast)
383{
384 size_t size = sizeof(rb_ast_t);
385 node_buffer_t *nb = ast->node_buffer;
386 rb_parser_ary_t *tokens = NULL;
387 struct rb_ast_local_table_link *link = NULL;
388 rb_parser_ary_t *script_lines = ast->body.script_lines;
389
390 long i;
391
392 if (nb) {
393 size += sizeof(node_buffer_t);
394 size += buffer_list_size(&nb->buffer_list);
395 link = nb->local_tables;
396 tokens = nb->tokens;
397 }
398
399 while (link) {
400 size += sizeof(struct rb_ast_local_table_link);
401 size += link->size * sizeof(ID);
402 link = link->next;
403 }
404
405 if (tokens) {
406 size += sizeof(rb_parser_ary_t);
407 for (i = 0; i < tokens->len; i++) {
408 size += sizeof(rb_parser_ast_token_t);
409 rb_parser_ast_token_t *token = tokens->data[i];
410 size += sizeof(rb_parser_string_t);
411 size += token->str->len + 1;
412 }
413 }
414
415 if (script_lines) {
416 size += sizeof(rb_parser_ary_t);
417 for (i = 0; i < script_lines->len; i++) {
418 size += sizeof(rb_parser_string_t);
419 size += ((rb_parser_string_t *)script_lines->data[i])->len + 1;
420 }
421 }
422
423 return size;
424}
425
426void
427rb_ast_dispose(rb_ast_t *ast)
428{
429 if (ast && ast->node_buffer) {
430 script_lines_free(ast, ast->body.script_lines);
431 ast->body.script_lines = NULL;
432 rb_node_buffer_free(ast, ast->node_buffer);
433 ast->node_buffer = 0;
434 }
435}
436
437VALUE
438rb_node_set_type(NODE *n, enum node_type t)
439{
440 return nd_init_type(n, t);
441}
442
443enum node_type
444rb_node_get_type(const NODE *n)
445{
446 return (enum node_type)nd_type(n);
447}
#define xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
int len
Length of the buffer.
Definition io.h:8
VALUE type(ANYARGS)
ANYARGS-ed function type.
Functions related to nodes in the AST.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40