2009-12-09 17:05:59 +03:00
|
|
|
/**********************************************************************
|
|
|
|
|
|
|
|
node.c - ruby node tree
|
|
|
|
|
|
|
|
$Author: mame $
|
|
|
|
created at: 09/12/06 21:23:44 JST
|
|
|
|
|
|
|
|
Copyright (C) 2009 Yusuke Endoh
|
|
|
|
|
|
|
|
**********************************************************************/
|
|
|
|
|
2023-05-28 14:00:20 +03:00
|
|
|
#ifdef UNIVERSAL_PARSER
|
|
|
|
#include <stddef.h>
|
|
|
|
#include "node.h"
|
|
|
|
#include "rubyparser.h"
|
2023-08-22 04:26:38 +03:00
|
|
|
#endif
|
|
|
|
|
2024-03-28 04:26:42 +03:00
|
|
|
#include "internal/variable.h"
|
|
|
|
|
2023-08-22 04:26:38 +03:00
|
|
|
#define NODE_BUF_DEFAULT_SIZE (sizeof(struct RNode) * 16)
|
|
|
|
|
|
|
|
static void
|
|
|
|
init_node_buffer_elem(node_buffer_elem_t *nbe, size_t allocated, void *xmalloc(size_t))
|
|
|
|
{
|
|
|
|
nbe->allocated = allocated;
|
|
|
|
nbe->used = 0;
|
|
|
|
nbe->len = 0;
|
|
|
|
nbe->nodes = xmalloc(allocated / sizeof(struct RNode) * sizeof(struct RNode *)); /* All node requires at least RNode */
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2024-04-04 17:19:31 +03:00
|
|
|
init_node_buffer_list(node_buffer_list_t *nb, node_buffer_elem_t *head, void *xmalloc(size_t))
|
2023-08-22 04:26:38 +03:00
|
|
|
{
|
|
|
|
init_node_buffer_elem(head, NODE_BUF_DEFAULT_SIZE, xmalloc);
|
|
|
|
nb->head = nb->last = head;
|
|
|
|
nb->head->next = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef UNIVERSAL_PARSER
|
|
|
|
#define ruby_xmalloc config->malloc
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef UNIVERSAL_PARSER
|
|
|
|
static node_buffer_t *
|
2024-01-14 11:55:11 +03:00
|
|
|
rb_node_buffer_new(const rb_parser_config_t *config)
|
2023-08-22 04:26:38 +03:00
|
|
|
#else
|
|
|
|
static node_buffer_t *
|
|
|
|
rb_node_buffer_new(void)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
const size_t bucket_size = offsetof(node_buffer_elem_t, buf) + NODE_BUF_DEFAULT_SIZE;
|
2024-04-04 17:19:31 +03:00
|
|
|
const size_t alloc_size = sizeof(node_buffer_t) + (bucket_size);
|
2023-08-22 04:26:38 +03:00
|
|
|
STATIC_ASSERT(
|
|
|
|
integer_overflow,
|
|
|
|
offsetof(node_buffer_elem_t, buf) + NODE_BUF_DEFAULT_SIZE
|
2024-04-04 17:19:31 +03:00
|
|
|
> sizeof(node_buffer_t) + sizeof(node_buffer_elem_t));
|
2023-08-22 04:26:38 +03:00
|
|
|
node_buffer_t *nb = ruby_xmalloc(alloc_size);
|
2024-04-04 17:19:31 +03:00
|
|
|
init_node_buffer_list(&nb->buffer_list, (node_buffer_elem_t*)&nb[1], ruby_xmalloc);
|
2023-08-22 04:26:38 +03:00
|
|
|
nb->local_tables = 0;
|
2024-02-16 11:45:22 +03:00
|
|
|
nb->tokens = 0;
|
2023-08-22 04:26:38 +03:00
|
|
|
return nb;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef UNIVERSAL_PARSER
|
|
|
|
#undef ruby_xmalloc
|
2024-04-27 10:28:52 +03:00
|
|
|
#define ruby_xmalloc ast->config->malloc
|
2023-05-28 14:00:20 +03:00
|
|
|
#undef xfree
|
2024-04-27 10:28:52 +03:00
|
|
|
#define xfree ast->config->free
|
|
|
|
#define rb_xmalloc_mul_add ast->config->xmalloc_mul_add
|
|
|
|
#define ruby_xrealloc(var,size) (ast->config->realloc_n((void *)var, 1, size))
|
2023-05-28 14:00:20 +03:00
|
|
|
#endif
|
2009-12-09 17:05:59 +03:00
|
|
|
|
2023-08-22 04:26:38 +03:00
|
|
|
typedef void node_itr_t(rb_ast_t *ast, void *ctx, NODE *node);
|
2023-09-20 17:51:39 +03:00
|
|
|
static void iterate_node_values(rb_ast_t *ast, node_buffer_list_t *nb, node_itr_t * func, void *ctx);
|
|
|
|
|
2017-10-24 09:16:31 +03:00
|
|
|
void
|
2023-08-22 04:26:38 +03:00
|
|
|
rb_node_init(NODE *n, enum node_type type)
|
2017-10-24 09:16:31 +03:00
|
|
|
{
|
2024-04-06 12:51:20 +03:00
|
|
|
RNODE(n)->flags = 0;
|
2023-08-22 04:26:38 +03:00
|
|
|
nd_init_type(RNODE(n), type);
|
|
|
|
RNODE(n)->nd_loc.beg_pos.lineno = 0;
|
|
|
|
RNODE(n)->nd_loc.beg_pos.column = 0;
|
|
|
|
RNODE(n)->nd_loc.end_pos.lineno = 0;
|
|
|
|
RNODE(n)->nd_loc.end_pos.column = 0;
|
|
|
|
RNODE(n)->node_id = -1;
|
2017-10-24 09:16:31 +03:00
|
|
|
}
|
|
|
|
|
2023-05-22 15:55:49 +03:00
|
|
|
const char *
|
2023-05-28 14:00:20 +03:00
|
|
|
rb_node_name(int node)
|
2023-05-22 15:55:49 +03:00
|
|
|
{
|
|
|
|
switch (node) {
|
|
|
|
#include "node_name.inc"
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-28 14:00:20 +03:00
|
|
|
#ifdef UNIVERSAL_PARSER
|
|
|
|
const char *
|
|
|
|
ruby_node_name(int node)
|
|
|
|
{
|
|
|
|
return rb_node_name(node);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
const char *
|
|
|
|
ruby_node_name(int node)
|
|
|
|
{
|
|
|
|
const char *name = rb_node_name(node);
|
2019-09-09 19:37:06 +03:00
|
|
|
|
2023-05-28 14:00:20 +03:00
|
|
|
if (!name) rb_bug("unknown node: %d", node);
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
#endif
|
2017-10-27 19:44:57 +03:00
|
|
|
|
2017-11-16 11:19:46 +03:00
|
|
|
static void
|
2023-05-28 14:00:20 +03:00
|
|
|
node_buffer_list_free(rb_ast_t *ast, node_buffer_list_t * nb)
|
2017-10-27 19:44:57 +03:00
|
|
|
{
|
|
|
|
node_buffer_elem_t *nbe = nb->head;
|
2018-01-16 18:12:09 +03:00
|
|
|
while (nbe != nb->last) {
|
2017-10-27 19:44:57 +03:00
|
|
|
void *buf = nbe;
|
2023-08-22 04:26:38 +03:00
|
|
|
xfree(nbe->nodes);
|
2017-10-27 19:44:57 +03:00
|
|
|
nbe = nbe->next;
|
|
|
|
xfree(buf);
|
|
|
|
}
|
2023-09-29 20:45:25 +03:00
|
|
|
|
|
|
|
/* The last node_buffer_elem_t is allocated in the node_buffer_t, so we
|
|
|
|
* only need to free the nodes. */
|
|
|
|
xfree(nbe->nodes);
|
2019-09-09 19:37:06 +03:00
|
|
|
}
|
|
|
|
|
2021-11-17 21:40:49 +03:00
|
|
|
struct rb_ast_local_table_link {
|
|
|
|
struct rb_ast_local_table_link *next;
|
|
|
|
// struct rb_ast_id_table {
|
|
|
|
int size;
|
|
|
|
ID ids[FLEX_ARY_LEN];
|
|
|
|
// }
|
|
|
|
};
|
|
|
|
|
2023-12-29 16:34:35 +03:00
|
|
|
static void
|
|
|
|
parser_string_free(rb_ast_t *ast, rb_parser_string_t *str)
|
|
|
|
{
|
2024-02-02 18:50:02 +03:00
|
|
|
if (!str) return;
|
|
|
|
xfree(str->ptr);
|
2023-12-29 16:34:35 +03:00
|
|
|
xfree(str);
|
|
|
|
}
|
|
|
|
|
2024-02-16 11:45:22 +03:00
|
|
|
static void
|
|
|
|
parser_ast_token_free(rb_ast_t *ast, rb_parser_ast_token_t *token)
|
|
|
|
{
|
|
|
|
if (!token) return;
|
|
|
|
parser_string_free(ast, token->str);
|
|
|
|
xfree(token);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
parser_tokens_free(rb_ast_t *ast, rb_parser_ary_t *tokens)
|
|
|
|
{
|
|
|
|
for (long i = 0; i < tokens->len; i++) {
|
|
|
|
parser_ast_token_free(ast, tokens->data[i]);
|
|
|
|
}
|
|
|
|
xfree(tokens->data);
|
|
|
|
xfree(tokens);
|
|
|
|
}
|
|
|
|
|
Change UNDEF Node structure
Change UNDEF Node to hold their items to keep the original grammar
structure.
For example:
```
undef a, b
```
Before:
```
@ NODE_BLOCK (id: 4, line: 1, location: (1,6)-(1,10))*
+- nd_head (1):
| @ NODE_UNDEF (id: 1, line: 1, location: (1,6)-(1,7))
| +- nd_undef:
| @ NODE_SYM (id: 0, line: 1, location: (1,6)-(1,7))
| +- string: :a
+- nd_head (2):
@ NODE_UNDEF (id: 3, line: 1, location: (1,9)-(1,10))
+- nd_undef:
@ NODE_SYM (id: 2, line: 1, location: (1,9)-(1,10))
+- string: :b
```
After:
```
@ NODE_UNDEF (id: 1, line: 1, location: (1,6)-(1,10))*
+- nd_undefs:
+- length: 2
+- element (0):
| @ NODE_SYM (id: 0, line: 1, location: (1,6)-(1,7))
| +- string: :a
+- element (1):
@ NODE_SYM (id: 2, line: 1, location: (1,9)-(1,10))
+- string: :b
```
2024-07-18 07:47:13 +03:00
|
|
|
static void
|
|
|
|
parser_nodes_free(rb_ast_t *ast, rb_parser_ary_t *nodes)
|
|
|
|
{
|
|
|
|
/* Do nothing for nodes because nodes are freed when rb_ast_t is freed */
|
|
|
|
xfree(nodes->data);
|
|
|
|
xfree(nodes);
|
|
|
|
}
|
|
|
|
|
2023-09-20 17:51:39 +03:00
|
|
|
static void
|
2023-08-22 04:26:38 +03:00
|
|
|
free_ast_value(rb_ast_t *ast, void *ctx, NODE *node)
|
2023-09-20 17:51:39 +03:00
|
|
|
{
|
|
|
|
switch (nd_type(node)) {
|
2024-02-02 18:50:02 +03:00
|
|
|
case NODE_STR:
|
|
|
|
parser_string_free(ast, RNODE_STR(node)->string);
|
|
|
|
break;
|
|
|
|
case NODE_DSTR:
|
|
|
|
parser_string_free(ast, RNODE_DSTR(node)->string);
|
|
|
|
break;
|
|
|
|
case NODE_XSTR:
|
|
|
|
parser_string_free(ast, RNODE_XSTR(node)->string);
|
|
|
|
break;
|
|
|
|
case NODE_DXSTR:
|
|
|
|
parser_string_free(ast, RNODE_DXSTR(node)->string);
|
|
|
|
break;
|
2023-12-31 19:31:28 +03:00
|
|
|
case NODE_SYM:
|
|
|
|
parser_string_free(ast, RNODE_SYM(node)->string);
|
|
|
|
break;
|
2024-02-10 04:05:18 +03:00
|
|
|
case NODE_REGX:
|
|
|
|
case NODE_MATCH:
|
|
|
|
parser_string_free(ast, RNODE_REGX(node)->string);
|
|
|
|
break;
|
2024-02-02 18:50:02 +03:00
|
|
|
case NODE_DSYM:
|
|
|
|
parser_string_free(ast, RNODE_DSYM(node)->string);
|
|
|
|
break;
|
|
|
|
case NODE_DREGX:
|
|
|
|
parser_string_free(ast, RNODE_DREGX(node)->string);
|
|
|
|
break;
|
2023-12-29 16:34:35 +03:00
|
|
|
case NODE_FILE:
|
|
|
|
parser_string_free(ast, RNODE_FILE(node)->path);
|
|
|
|
break;
|
2024-01-05 06:03:11 +03:00
|
|
|
case NODE_INTEGER:
|
|
|
|
xfree(RNODE_INTEGER(node)->val);
|
|
|
|
break;
|
|
|
|
case NODE_FLOAT:
|
|
|
|
xfree(RNODE_FLOAT(node)->val);
|
|
|
|
break;
|
|
|
|
case NODE_RATIONAL:
|
|
|
|
xfree(RNODE_RATIONAL(node)->val);
|
|
|
|
break;
|
|
|
|
case NODE_IMAGINARY:
|
|
|
|
xfree(RNODE_IMAGINARY(node)->val);
|
|
|
|
break;
|
Change UNDEF Node structure
Change UNDEF Node to hold their items to keep the original grammar
structure.
For example:
```
undef a, b
```
Before:
```
@ NODE_BLOCK (id: 4, line: 1, location: (1,6)-(1,10))*
+- nd_head (1):
| @ NODE_UNDEF (id: 1, line: 1, location: (1,6)-(1,7))
| +- nd_undef:
| @ NODE_SYM (id: 0, line: 1, location: (1,6)-(1,7))
| +- string: :a
+- nd_head (2):
@ NODE_UNDEF (id: 3, line: 1, location: (1,9)-(1,10))
+- nd_undef:
@ NODE_SYM (id: 2, line: 1, location: (1,9)-(1,10))
+- string: :b
```
After:
```
@ NODE_UNDEF (id: 1, line: 1, location: (1,6)-(1,10))*
+- nd_undefs:
+- length: 2
+- element (0):
| @ NODE_SYM (id: 0, line: 1, location: (1,6)-(1,7))
| +- string: :a
+- element (1):
@ NODE_SYM (id: 2, line: 1, location: (1,9)-(1,10))
+- string: :b
```
2024-07-18 07:47:13 +03:00
|
|
|
case NODE_UNDEF:
|
|
|
|
parser_nodes_free(ast, RNODE_UNDEF(node)->nd_undefs);
|
|
|
|
break;
|
2023-10-29 18:19:43 +03:00
|
|
|
default:
|
2023-09-20 17:51:39 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-09 19:37:06 +03:00
|
|
|
static void
|
2023-05-28 14:00:20 +03:00
|
|
|
rb_node_buffer_free(rb_ast_t *ast, node_buffer_t *nb)
|
2019-09-09 19:37:06 +03:00
|
|
|
{
|
2024-04-27 10:28:52 +03:00
|
|
|
if (nb && nb->tokens) {
|
|
|
|
parser_tokens_free(ast, nb->tokens);
|
2024-02-16 11:45:22 +03:00
|
|
|
}
|
2024-04-04 17:19:31 +03:00
|
|
|
iterate_node_values(ast, &nb->buffer_list, free_ast_value, NULL);
|
|
|
|
node_buffer_list_free(ast, &nb->buffer_list);
|
2021-11-17 21:40:49 +03:00
|
|
|
struct rb_ast_local_table_link *local_table = nb->local_tables;
|
2020-07-24 02:00:28 +03:00
|
|
|
while (local_table) {
|
2021-11-17 21:40:49 +03:00
|
|
|
struct rb_ast_local_table_link *next_table = local_table->next;
|
2020-07-24 02:00:28 +03:00
|
|
|
xfree(local_table);
|
|
|
|
local_table = next_table;
|
|
|
|
}
|
2017-10-27 19:44:57 +03:00
|
|
|
xfree(nb);
|
|
|
|
}
|
|
|
|
|
2023-08-22 04:26:38 +03:00
|
|
|
#define buf_add_offset(nbe, offset) ((char *)(nbe->buf) + (offset))
|
|
|
|
|
2019-09-09 19:37:06 +03:00
|
|
|
static NODE *
|
2023-08-22 04:26:38 +03:00
|
|
|
ast_newnode_in_bucket(rb_ast_t *ast, node_buffer_list_t *nb, size_t size, size_t alignment)
|
2017-10-27 19:44:57 +03:00
|
|
|
{
|
2023-08-22 04:26:38 +03:00
|
|
|
size_t padding;
|
|
|
|
NODE *ptr;
|
|
|
|
|
|
|
|
padding = alignment - (size_t)buf_add_offset(nb->head, nb->head->used) % alignment;
|
|
|
|
padding = padding == alignment ? 0 : padding;
|
|
|
|
|
|
|
|
if (nb->head->used + size + padding > nb->head->allocated) {
|
|
|
|
size_t n = nb->head->allocated * 2;
|
2017-10-27 19:44:57 +03:00
|
|
|
node_buffer_elem_t *nbe;
|
2023-08-22 04:26:38 +03:00
|
|
|
nbe = rb_xmalloc_mul_add(n, sizeof(char *), offsetof(node_buffer_elem_t, buf));
|
|
|
|
init_node_buffer_elem(nbe, n, ruby_xmalloc);
|
2017-10-27 19:44:57 +03:00
|
|
|
nbe->next = nb->head;
|
|
|
|
nb->head = nbe;
|
2023-08-22 04:26:38 +03:00
|
|
|
padding = 0; /* malloc returns aligned address then no need to add padding */
|
2017-10-27 19:44:57 +03:00
|
|
|
}
|
2023-08-22 04:26:38 +03:00
|
|
|
|
|
|
|
ptr = (NODE *)buf_add_offset(nb->head, nb->head->used + padding);
|
|
|
|
nb->head->used += (size + padding);
|
|
|
|
nb->head->nodes[nb->head->len++] = ptr;
|
|
|
|
return ptr;
|
2017-10-27 19:44:57 +03:00
|
|
|
}
|
|
|
|
|
2021-01-14 09:42:45 +03:00
|
|
|
NODE *
|
2023-08-22 04:26:38 +03:00
|
|
|
rb_ast_newnode(rb_ast_t *ast, enum node_type type, size_t size, size_t alignment)
|
2021-01-14 09:42:45 +03:00
|
|
|
{
|
|
|
|
node_buffer_t *nb = ast->node_buffer;
|
2024-04-04 17:19:31 +03:00
|
|
|
node_buffer_list_t *bucket = &nb->buffer_list;
|
2023-08-22 04:26:38 +03:00
|
|
|
return ast_newnode_in_bucket(ast, bucket, size, alignment);
|
2021-01-14 09:42:45 +03:00
|
|
|
}
|
|
|
|
|
2021-11-17 21:40:49 +03:00
|
|
|
rb_ast_id_table_t *
|
|
|
|
rb_ast_new_local_table(rb_ast_t *ast, int size)
|
|
|
|
{
|
|
|
|
size_t alloc_size = sizeof(struct rb_ast_local_table_link) + size * sizeof(ID);
|
|
|
|
struct rb_ast_local_table_link *link = ruby_xmalloc(alloc_size);
|
|
|
|
link->next = ast->node_buffer->local_tables;
|
|
|
|
ast->node_buffer->local_tables = link;
|
|
|
|
link->size = size;
|
|
|
|
|
|
|
|
return (rb_ast_id_table_t *) &link->size;
|
|
|
|
}
|
|
|
|
|
|
|
|
rb_ast_id_table_t *
|
|
|
|
rb_ast_resize_latest_local_table(rb_ast_t *ast, int size)
|
2020-07-24 02:00:28 +03:00
|
|
|
{
|
2021-11-17 21:40:49 +03:00
|
|
|
struct rb_ast_local_table_link *link = ast->node_buffer->local_tables;
|
|
|
|
size_t alloc_size = sizeof(struct rb_ast_local_table_link) + size * sizeof(ID);
|
|
|
|
link = ruby_xrealloc(link, alloc_size);
|
|
|
|
ast->node_buffer->local_tables = link;
|
|
|
|
link->size = size;
|
|
|
|
|
|
|
|
return (rb_ast_id_table_t *) &link->size;
|
2020-07-24 02:00:28 +03:00
|
|
|
}
|
|
|
|
|
2017-10-27 19:44:57 +03:00
|
|
|
void
|
2017-10-29 18:51:23 +03:00
|
|
|
rb_ast_delete_node(rb_ast_t *ast, NODE *n)
|
2017-10-27 19:44:57 +03:00
|
|
|
{
|
|
|
|
(void)ast;
|
|
|
|
(void)n;
|
|
|
|
/* should we implement freelist? */
|
|
|
|
}
|
|
|
|
|
2023-05-28 14:00:20 +03:00
|
|
|
#ifdef UNIVERSAL_PARSER
|
|
|
|
rb_ast_t *
|
2024-01-14 11:55:11 +03:00
|
|
|
rb_ast_new(const rb_parser_config_t *config)
|
2023-05-28 14:00:20 +03:00
|
|
|
{
|
|
|
|
node_buffer_t *nb = rb_node_buffer_new(config);
|
2024-04-28 06:45:30 +03:00
|
|
|
rb_ast_t *ast = (rb_ast_t *)config->calloc(1, sizeof(rb_ast_t));
|
2024-04-27 10:28:52 +03:00
|
|
|
ast->config = config;
|
2024-04-28 06:45:30 +03:00
|
|
|
ast->node_buffer = nb;
|
2024-04-27 10:28:52 +03:00
|
|
|
return ast;
|
2023-05-28 14:00:20 +03:00
|
|
|
}
|
|
|
|
#else
|
2017-10-29 18:51:23 +03:00
|
|
|
rb_ast_t *
|
2017-10-27 19:44:57 +03:00
|
|
|
rb_ast_new(void)
|
|
|
|
{
|
2018-08-22 13:38:55 +03:00
|
|
|
node_buffer_t *nb = rb_node_buffer_new();
|
[Universal parser] Decouple IMEMO from rb_ast_t
This patch removes the `VALUE flags` member from the `rb_ast_t` structure making `rb_ast_t` no longer an IMEMO object.
## Background
We are trying to make the Ruby parser generated from parse.y a universal parser that can be used by other implementations such as mruby.
To achieve this, it is necessary to exclude VALUE and IMEMO from parse.y, AST, and NODE.
## Summary (file by file)
- `rubyparser.h`
- Remove the `VALUE flags` member from `rb_ast_t`
- `ruby_parser.c` and `internal/ruby_parser.h`
- Use TypedData_Make_Struct VALUE which wraps `rb_ast_t` `in ast_alloc()` so that GC can manage it
- You can retrieve `rb_ast_t` from the VALUE by `rb_ruby_ast_data_get()`
- Change the return type of `rb_parser_compile_XXXX()` functions from `rb_ast_t *` to `VALUE`
- rb_ruby_ast_new() which internally `calls ast_alloc()` is to create VALUE vast outside ruby_parser.c
- `iseq.c` and `vm_core.h`
- Amend the first parameter of `rb_iseq_new_XXXX()` functions from `rb_ast_body_t *` to `VALUE`
- This keeps the VALUE of AST on the machine stack to prevent being removed by GC
- `ast.c`
- Almost all change is replacement `rb_ast_t *ast` with `VALUE vast` (sorry for the big diff)
- Fix `node_memsize()`
- Now it includes `rb_ast_local_table_link`, `tokens` and script_lines
- `compile.c`, `load.c`, `node.c`, `parse.y`, `proc.c`, `ruby.c`, `template/prelude.c.tmpl`, `vm.c` and `vm_eval.c`
- Follow-up due to the above changes
- `imemo.{c|h}`
- If an object with `imemo_ast` appears, considers it a bug
Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
2024-04-16 12:42:42 +03:00
|
|
|
rb_ast_t *ast = ruby_xcalloc(1, sizeof(rb_ast_t));
|
|
|
|
ast->node_buffer = nb;
|
|
|
|
return ast;
|
2017-10-27 19:44:57 +03:00
|
|
|
}
|
2023-05-28 14:00:20 +03:00
|
|
|
#endif
|
2017-10-27 19:44:57 +03:00
|
|
|
|
2019-09-09 19:37:06 +03:00
|
|
|
static void
|
2023-05-28 14:00:20 +03:00
|
|
|
iterate_buffer_elements(rb_ast_t *ast, node_buffer_elem_t *nbe, long len, node_itr_t *func, void *ctx)
|
2019-09-09 19:37:06 +03:00
|
|
|
{
|
|
|
|
long cursor;
|
|
|
|
for (cursor = 0; cursor < len; cursor++) {
|
2023-08-22 04:26:38 +03:00
|
|
|
func(ast, ctx, nbe->nodes[cursor]);
|
2019-09-09 19:37:06 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-05-28 14:00:20 +03:00
|
|
|
iterate_node_values(rb_ast_t *ast, node_buffer_list_t *nb, node_itr_t * func, void *ctx)
|
2019-09-09 19:37:06 +03:00
|
|
|
{
|
|
|
|
node_buffer_elem_t *nbe = nb->head;
|
|
|
|
|
|
|
|
while (nbe) {
|
2023-05-28 14:00:20 +03:00
|
|
|
iterate_buffer_elements(ast, nbe, nbe->len, func, ctx);
|
2019-09-09 19:37:06 +03:00
|
|
|
nbe = nbe->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-28 04:26:42 +03:00
|
|
|
static void
|
|
|
|
script_lines_free(rb_ast_t *ast, rb_parser_ary_t *script_lines)
|
2017-10-27 19:44:57 +03:00
|
|
|
{
|
2024-04-26 15:43:35 +03:00
|
|
|
if (!script_lines) return;
|
2024-03-28 04:26:42 +03:00
|
|
|
for (long i = 0; i < script_lines->len; i++) {
|
|
|
|
parser_string_free(ast, (rb_parser_string_t *)script_lines->data[i]);
|
2019-09-09 19:37:06 +03:00
|
|
|
}
|
2024-03-28 04:26:42 +03:00
|
|
|
xfree(script_lines->data);
|
|
|
|
xfree(script_lines);
|
2017-10-27 19:44:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2017-10-29 18:51:23 +03:00
|
|
|
rb_ast_free(rb_ast_t *ast)
|
2017-10-27 19:44:57 +03:00
|
|
|
{
|
[Universal parser] Decouple IMEMO from rb_ast_t
This patch removes the `VALUE flags` member from the `rb_ast_t` structure making `rb_ast_t` no longer an IMEMO object.
## Background
We are trying to make the Ruby parser generated from parse.y a universal parser that can be used by other implementations such as mruby.
To achieve this, it is necessary to exclude VALUE and IMEMO from parse.y, AST, and NODE.
## Summary (file by file)
- `rubyparser.h`
- Remove the `VALUE flags` member from `rb_ast_t`
- `ruby_parser.c` and `internal/ruby_parser.h`
- Use TypedData_Make_Struct VALUE which wraps `rb_ast_t` `in ast_alloc()` so that GC can manage it
- You can retrieve `rb_ast_t` from the VALUE by `rb_ruby_ast_data_get()`
- Change the return type of `rb_parser_compile_XXXX()` functions from `rb_ast_t *` to `VALUE`
- rb_ruby_ast_new() which internally `calls ast_alloc()` is to create VALUE vast outside ruby_parser.c
- `iseq.c` and `vm_core.h`
- Amend the first parameter of `rb_iseq_new_XXXX()` functions from `rb_ast_body_t *` to `VALUE`
- This keeps the VALUE of AST on the machine stack to prevent being removed by GC
- `ast.c`
- Almost all change is replacement `rb_ast_t *ast` with `VALUE vast` (sorry for the big diff)
- Fix `node_memsize()`
- Now it includes `rb_ast_local_table_link`, `tokens` and script_lines
- `compile.c`, `load.c`, `node.c`, `parse.y`, `proc.c`, `ruby.c`, `template/prelude.c.tmpl`, `vm.c` and `vm_eval.c`
- Follow-up due to the above changes
- `imemo.{c|h}`
- If an object with `imemo_ast` appears, considers it a bug
Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
2024-04-16 12:42:42 +03:00
|
|
|
rb_ast_dispose(ast);
|
|
|
|
xfree(ast);
|
2017-10-27 19:44:57 +03:00
|
|
|
}
|
|
|
|
|
2019-09-09 19:37:06 +03:00
|
|
|
static size_t
|
|
|
|
buffer_list_size(node_buffer_list_t *nb)
|
|
|
|
{
|
|
|
|
size_t size = 0;
|
|
|
|
node_buffer_elem_t *nbe = nb->head;
|
|
|
|
while (nbe != nb->last) {
|
2023-08-22 04:26:38 +03:00
|
|
|
size += offsetof(node_buffer_elem_t, buf) + nbe->used;
|
2019-09-09 19:37:06 +03:00
|
|
|
nbe = nbe->next;
|
|
|
|
}
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2019-04-23 01:24:52 +03:00
|
|
|
size_t
|
|
|
|
rb_ast_memsize(const rb_ast_t *ast)
|
|
|
|
{
|
[Universal parser] Decouple IMEMO from rb_ast_t
This patch removes the `VALUE flags` member from the `rb_ast_t` structure making `rb_ast_t` no longer an IMEMO object.
## Background
We are trying to make the Ruby parser generated from parse.y a universal parser that can be used by other implementations such as mruby.
To achieve this, it is necessary to exclude VALUE and IMEMO from parse.y, AST, and NODE.
## Summary (file by file)
- `rubyparser.h`
- Remove the `VALUE flags` member from `rb_ast_t`
- `ruby_parser.c` and `internal/ruby_parser.h`
- Use TypedData_Make_Struct VALUE which wraps `rb_ast_t` `in ast_alloc()` so that GC can manage it
- You can retrieve `rb_ast_t` from the VALUE by `rb_ruby_ast_data_get()`
- Change the return type of `rb_parser_compile_XXXX()` functions from `rb_ast_t *` to `VALUE`
- rb_ruby_ast_new() which internally `calls ast_alloc()` is to create VALUE vast outside ruby_parser.c
- `iseq.c` and `vm_core.h`
- Amend the first parameter of `rb_iseq_new_XXXX()` functions from `rb_ast_body_t *` to `VALUE`
- This keeps the VALUE of AST on the machine stack to prevent being removed by GC
- `ast.c`
- Almost all change is replacement `rb_ast_t *ast` with `VALUE vast` (sorry for the big diff)
- Fix `node_memsize()`
- Now it includes `rb_ast_local_table_link`, `tokens` and script_lines
- `compile.c`, `load.c`, `node.c`, `parse.y`, `proc.c`, `ruby.c`, `template/prelude.c.tmpl`, `vm.c` and `vm_eval.c`
- Follow-up due to the above changes
- `imemo.{c|h}`
- If an object with `imemo_ast` appears, considers it a bug
Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
2024-04-16 12:42:42 +03:00
|
|
|
size_t size = sizeof(rb_ast_t);
|
2019-04-23 01:24:52 +03:00
|
|
|
node_buffer_t *nb = ast->node_buffer;
|
[Universal parser] Decouple IMEMO from rb_ast_t
This patch removes the `VALUE flags` member from the `rb_ast_t` structure making `rb_ast_t` no longer an IMEMO object.
## Background
We are trying to make the Ruby parser generated from parse.y a universal parser that can be used by other implementations such as mruby.
To achieve this, it is necessary to exclude VALUE and IMEMO from parse.y, AST, and NODE.
## Summary (file by file)
- `rubyparser.h`
- Remove the `VALUE flags` member from `rb_ast_t`
- `ruby_parser.c` and `internal/ruby_parser.h`
- Use TypedData_Make_Struct VALUE which wraps `rb_ast_t` `in ast_alloc()` so that GC can manage it
- You can retrieve `rb_ast_t` from the VALUE by `rb_ruby_ast_data_get()`
- Change the return type of `rb_parser_compile_XXXX()` functions from `rb_ast_t *` to `VALUE`
- rb_ruby_ast_new() which internally `calls ast_alloc()` is to create VALUE vast outside ruby_parser.c
- `iseq.c` and `vm_core.h`
- Amend the first parameter of `rb_iseq_new_XXXX()` functions from `rb_ast_body_t *` to `VALUE`
- This keeps the VALUE of AST on the machine stack to prevent being removed by GC
- `ast.c`
- Almost all change is replacement `rb_ast_t *ast` with `VALUE vast` (sorry for the big diff)
- Fix `node_memsize()`
- Now it includes `rb_ast_local_table_link`, `tokens` and script_lines
- `compile.c`, `load.c`, `node.c`, `parse.y`, `proc.c`, `ruby.c`, `template/prelude.c.tmpl`, `vm.c` and `vm_eval.c`
- Follow-up due to the above changes
- `imemo.{c|h}`
- If an object with `imemo_ast` appears, considers it a bug
Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
2024-04-16 12:42:42 +03:00
|
|
|
rb_parser_ary_t *tokens = NULL;
|
|
|
|
struct rb_ast_local_table_link *link = NULL;
|
|
|
|
rb_parser_ary_t *script_lines = ast->body.script_lines;
|
|
|
|
|
|
|
|
long i;
|
2019-04-23 01:24:52 +03:00
|
|
|
|
|
|
|
if (nb) {
|
2023-08-22 04:26:38 +03:00
|
|
|
size += sizeof(node_buffer_t);
|
2024-04-04 17:19:31 +03:00
|
|
|
size += buffer_list_size(&nb->buffer_list);
|
[Universal parser] Decouple IMEMO from rb_ast_t
This patch removes the `VALUE flags` member from the `rb_ast_t` structure making `rb_ast_t` no longer an IMEMO object.
## Background
We are trying to make the Ruby parser generated from parse.y a universal parser that can be used by other implementations such as mruby.
To achieve this, it is necessary to exclude VALUE and IMEMO from parse.y, AST, and NODE.
## Summary (file by file)
- `rubyparser.h`
- Remove the `VALUE flags` member from `rb_ast_t`
- `ruby_parser.c` and `internal/ruby_parser.h`
- Use TypedData_Make_Struct VALUE which wraps `rb_ast_t` `in ast_alloc()` so that GC can manage it
- You can retrieve `rb_ast_t` from the VALUE by `rb_ruby_ast_data_get()`
- Change the return type of `rb_parser_compile_XXXX()` functions from `rb_ast_t *` to `VALUE`
- rb_ruby_ast_new() which internally `calls ast_alloc()` is to create VALUE vast outside ruby_parser.c
- `iseq.c` and `vm_core.h`
- Amend the first parameter of `rb_iseq_new_XXXX()` functions from `rb_ast_body_t *` to `VALUE`
- This keeps the VALUE of AST on the machine stack to prevent being removed by GC
- `ast.c`
- Almost all change is replacement `rb_ast_t *ast` with `VALUE vast` (sorry for the big diff)
- Fix `node_memsize()`
- Now it includes `rb_ast_local_table_link`, `tokens` and script_lines
- `compile.c`, `load.c`, `node.c`, `parse.y`, `proc.c`, `ruby.c`, `template/prelude.c.tmpl`, `vm.c` and `vm_eval.c`
- Follow-up due to the above changes
- `imemo.{c|h}`
- If an object with `imemo_ast` appears, considers it a bug
Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
2024-04-16 12:42:42 +03:00
|
|
|
link = nb->local_tables;
|
|
|
|
tokens = nb->tokens;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (link) {
|
|
|
|
size += sizeof(struct rb_ast_local_table_link);
|
|
|
|
size += link->size * sizeof(ID);
|
|
|
|
link = link->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tokens) {
|
|
|
|
size += sizeof(rb_parser_ary_t);
|
|
|
|
for (i = 0; i < tokens->len; i++) {
|
|
|
|
size += sizeof(rb_parser_ast_token_t);
|
|
|
|
rb_parser_ast_token_t *token = tokens->data[i];
|
|
|
|
size += sizeof(rb_parser_string_t);
|
|
|
|
size += token->str->len + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-26 15:43:35 +03:00
|
|
|
if (script_lines) {
|
[Universal parser] Decouple IMEMO from rb_ast_t
This patch removes the `VALUE flags` member from the `rb_ast_t` structure making `rb_ast_t` no longer an IMEMO object.
## Background
We are trying to make the Ruby parser generated from parse.y a universal parser that can be used by other implementations such as mruby.
To achieve this, it is necessary to exclude VALUE and IMEMO from parse.y, AST, and NODE.
## Summary (file by file)
- `rubyparser.h`
- Remove the `VALUE flags` member from `rb_ast_t`
- `ruby_parser.c` and `internal/ruby_parser.h`
- Use TypedData_Make_Struct VALUE which wraps `rb_ast_t` `in ast_alloc()` so that GC can manage it
- You can retrieve `rb_ast_t` from the VALUE by `rb_ruby_ast_data_get()`
- Change the return type of `rb_parser_compile_XXXX()` functions from `rb_ast_t *` to `VALUE`
- rb_ruby_ast_new() which internally `calls ast_alloc()` is to create VALUE vast outside ruby_parser.c
- `iseq.c` and `vm_core.h`
- Amend the first parameter of `rb_iseq_new_XXXX()` functions from `rb_ast_body_t *` to `VALUE`
- This keeps the VALUE of AST on the machine stack to prevent being removed by GC
- `ast.c`
- Almost all change is replacement `rb_ast_t *ast` with `VALUE vast` (sorry for the big diff)
- Fix `node_memsize()`
- Now it includes `rb_ast_local_table_link`, `tokens` and script_lines
- `compile.c`, `load.c`, `node.c`, `parse.y`, `proc.c`, `ruby.c`, `template/prelude.c.tmpl`, `vm.c` and `vm_eval.c`
- Follow-up due to the above changes
- `imemo.{c|h}`
- If an object with `imemo_ast` appears, considers it a bug
Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
2024-04-16 12:42:42 +03:00
|
|
|
size += sizeof(rb_parser_ary_t);
|
|
|
|
for (i = 0; i < script_lines->len; i++) {
|
|
|
|
size += sizeof(rb_parser_string_t);
|
|
|
|
size += ((rb_parser_string_t *)script_lines->data[i])->len + 1;
|
|
|
|
}
|
2019-04-23 01:24:52 +03:00
|
|
|
}
|
[Universal parser] Decouple IMEMO from rb_ast_t
This patch removes the `VALUE flags` member from the `rb_ast_t` structure making `rb_ast_t` no longer an IMEMO object.
## Background
We are trying to make the Ruby parser generated from parse.y a universal parser that can be used by other implementations such as mruby.
To achieve this, it is necessary to exclude VALUE and IMEMO from parse.y, AST, and NODE.
## Summary (file by file)
- `rubyparser.h`
- Remove the `VALUE flags` member from `rb_ast_t`
- `ruby_parser.c` and `internal/ruby_parser.h`
- Use TypedData_Make_Struct VALUE which wraps `rb_ast_t` `in ast_alloc()` so that GC can manage it
- You can retrieve `rb_ast_t` from the VALUE by `rb_ruby_ast_data_get()`
- Change the return type of `rb_parser_compile_XXXX()` functions from `rb_ast_t *` to `VALUE`
- rb_ruby_ast_new() which internally `calls ast_alloc()` is to create VALUE vast outside ruby_parser.c
- `iseq.c` and `vm_core.h`
- Amend the first parameter of `rb_iseq_new_XXXX()` functions from `rb_ast_body_t *` to `VALUE`
- This keeps the VALUE of AST on the machine stack to prevent being removed by GC
- `ast.c`
- Almost all change is replacement `rb_ast_t *ast` with `VALUE vast` (sorry for the big diff)
- Fix `node_memsize()`
- Now it includes `rb_ast_local_table_link`, `tokens` and script_lines
- `compile.c`, `load.c`, `node.c`, `parse.y`, `proc.c`, `ruby.c`, `template/prelude.c.tmpl`, `vm.c` and `vm_eval.c`
- Follow-up due to the above changes
- `imemo.{c|h}`
- If an object with `imemo_ast` appears, considers it a bug
Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
2024-04-16 12:42:42 +03:00
|
|
|
|
2019-04-23 01:24:52 +03:00
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2017-10-27 19:44:57 +03:00
|
|
|
void
|
2017-10-29 18:51:23 +03:00
|
|
|
rb_ast_dispose(rb_ast_t *ast)
|
2017-10-27 19:44:57 +03:00
|
|
|
{
|
[Universal parser] Decouple IMEMO from rb_ast_t
This patch removes the `VALUE flags` member from the `rb_ast_t` structure making `rb_ast_t` no longer an IMEMO object.
## Background
We are trying to make the Ruby parser generated from parse.y a universal parser that can be used by other implementations such as mruby.
To achieve this, it is necessary to exclude VALUE and IMEMO from parse.y, AST, and NODE.
## Summary (file by file)
- `rubyparser.h`
- Remove the `VALUE flags` member from `rb_ast_t`
- `ruby_parser.c` and `internal/ruby_parser.h`
- Use TypedData_Make_Struct VALUE which wraps `rb_ast_t` `in ast_alloc()` so that GC can manage it
- You can retrieve `rb_ast_t` from the VALUE by `rb_ruby_ast_data_get()`
- Change the return type of `rb_parser_compile_XXXX()` functions from `rb_ast_t *` to `VALUE`
- rb_ruby_ast_new() which internally `calls ast_alloc()` is to create VALUE vast outside ruby_parser.c
- `iseq.c` and `vm_core.h`
- Amend the first parameter of `rb_iseq_new_XXXX()` functions from `rb_ast_body_t *` to `VALUE`
- This keeps the VALUE of AST on the machine stack to prevent being removed by GC
- `ast.c`
- Almost all change is replacement `rb_ast_t *ast` with `VALUE vast` (sorry for the big diff)
- Fix `node_memsize()`
- Now it includes `rb_ast_local_table_link`, `tokens` and script_lines
- `compile.c`, `load.c`, `node.c`, `parse.y`, `proc.c`, `ruby.c`, `template/prelude.c.tmpl`, `vm.c` and `vm_eval.c`
- Follow-up due to the above changes
- `imemo.{c|h}`
- If an object with `imemo_ast` appears, considers it a bug
Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
2024-04-16 12:42:42 +03:00
|
|
|
if (ast && ast->node_buffer) {
|
2024-04-26 15:43:35 +03:00
|
|
|
script_lines_free(ast, ast->body.script_lines);
|
|
|
|
ast->body.script_lines = NULL;
|
[Universal parser] Decouple IMEMO from rb_ast_t
This patch removes the `VALUE flags` member from the `rb_ast_t` structure making `rb_ast_t` no longer an IMEMO object.
## Background
We are trying to make the Ruby parser generated from parse.y a universal parser that can be used by other implementations such as mruby.
To achieve this, it is necessary to exclude VALUE and IMEMO from parse.y, AST, and NODE.
## Summary (file by file)
- `rubyparser.h`
- Remove the `VALUE flags` member from `rb_ast_t`
- `ruby_parser.c` and `internal/ruby_parser.h`
- Use TypedData_Make_Struct VALUE which wraps `rb_ast_t` `in ast_alloc()` so that GC can manage it
- You can retrieve `rb_ast_t` from the VALUE by `rb_ruby_ast_data_get()`
- Change the return type of `rb_parser_compile_XXXX()` functions from `rb_ast_t *` to `VALUE`
- rb_ruby_ast_new() which internally `calls ast_alloc()` is to create VALUE vast outside ruby_parser.c
- `iseq.c` and `vm_core.h`
- Amend the first parameter of `rb_iseq_new_XXXX()` functions from `rb_ast_body_t *` to `VALUE`
- This keeps the VALUE of AST on the machine stack to prevent being removed by GC
- `ast.c`
- Almost all change is replacement `rb_ast_t *ast` with `VALUE vast` (sorry for the big diff)
- Fix `node_memsize()`
- Now it includes `rb_ast_local_table_link`, `tokens` and script_lines
- `compile.c`, `load.c`, `node.c`, `parse.y`, `proc.c`, `ruby.c`, `template/prelude.c.tmpl`, `vm.c` and `vm_eval.c`
- Follow-up due to the above changes
- `imemo.{c|h}`
- If an object with `imemo_ast` appears, considers it a bug
Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
2024-04-16 12:42:42 +03:00
|
|
|
rb_node_buffer_free(ast, ast->node_buffer);
|
|
|
|
ast->node_buffer = 0;
|
|
|
|
}
|
2017-10-27 19:44:57 +03:00
|
|
|
}
|
|
|
|
|
2023-05-28 14:00:20 +03:00
|
|
|
VALUE
|
|
|
|
rb_node_set_type(NODE *n, enum node_type t)
|
|
|
|
{
|
|
|
|
return nd_init_type(n, t);
|
|
|
|
}
|