diff options
Diffstat (limited to 'yarp/templates/ext/yarp/api_node.c.erb')
-rw-r--r-- | yarp/templates/ext/yarp/api_node.c.erb | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/yarp/templates/ext/yarp/api_node.c.erb b/yarp/templates/ext/yarp/api_node.c.erb new file mode 100644 index 0000000000..599bf2e9ff --- /dev/null +++ b/yarp/templates/ext/yarp/api_node.c.erb @@ -0,0 +1,204 @@ +#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>" +#include "yarp/extension.h" + +extern VALUE rb_cYARP; +extern VALUE rb_cYARPNode; +extern VALUE rb_cYARPSource; +extern VALUE rb_cYARPToken; +extern VALUE rb_cYARPLocation; + +<%- nodes.each do |node| -%> +static VALUE rb_cYARP<%= node.name %>; +<%- end -%> + +static VALUE +yp_location_new(yp_parser_t *parser, const char *start, const char *end, VALUE source) { + VALUE argv[] = { source, LONG2FIX(start - parser->start), LONG2FIX(end - start) }; + return rb_class_new_instance(3, argv, rb_cYARPLocation); +} + +VALUE +yp_token_new(yp_parser_t *parser, yp_token_t *token, rb_encoding *encoding, VALUE source) { + ID type = rb_intern(yp_token_type_to_str(token->type)); + VALUE location = yp_location_new(parser, token->start, token->end, source); + + VALUE argv[] = { + ID2SYM(type), + rb_enc_str_new(token->start, token->end - token->start, encoding), + location + }; + + return rb_class_new_instance(3, argv, rb_cYARPToken); +} + +static VALUE +yp_string_new(yp_string_t *string, rb_encoding *encoding) { + return rb_enc_str_new(yp_string_source(string), yp_string_length(string), encoding); +} + +// Create a YARP::Source object from the given parser. +VALUE +yp_source_new(yp_parser_t *parser) { + VALUE source = rb_str_new(parser->start, parser->end - parser->start); + VALUE offsets = rb_ary_new_capa(parser->newline_list.size); + + for (size_t index = 0; index < parser->newline_list.size; index++) { + rb_ary_push(offsets, INT2FIX(parser->newline_list.offsets[index])); + } + + VALUE source_argv[] = { source, offsets }; + return rb_class_new_instance(2, source_argv, rb_cYARPSource); +} + +typedef struct yp_node_stack_node { + struct yp_node_stack_node *prev; + yp_node_t *visit; + bool visited; +} yp_node_stack_node_t; + +static void +yp_node_stack_push(yp_node_stack_node_t **stack, yp_node_t *visit) { + yp_node_stack_node_t *node = malloc(sizeof(yp_node_stack_node_t)); + node->prev = *stack; + node->visit = visit; + node->visited = false; + *stack = node; +} + +static yp_node_t * +yp_node_stack_pop(yp_node_stack_node_t **stack) { + yp_node_stack_node_t *current = *stack; + yp_node_t *visit = current->visit; + + *stack = current->prev; + free(current); + + return visit; +} + +VALUE +yp_ast_new(yp_parser_t *parser, yp_node_t *node, rb_encoding *encoding) { + VALUE source = yp_source_new(parser); + ID *constants = calloc(parser->constant_pool.size, sizeof(ID)); + + for (size_t index = 0; index < parser->constant_pool.capacity; index++) { + yp_constant_t constant = parser->constant_pool.constants[index]; + + if (constant.id != 0) { + constants[constant.id - 1] = rb_intern3(constant.start, constant.length, encoding); + } + } + + yp_node_stack_node_t *node_stack = NULL; + yp_node_stack_push(&node_stack, node); + VALUE value_stack = rb_ary_new(); + + while (node_stack != NULL) { + if (!node_stack->visited) { + if (node_stack->visit == NULL) { + yp_node_stack_pop(&node_stack); + rb_ary_push(value_stack, Qnil); + continue; + } + + yp_node_t *node = node_stack->visit; + node_stack->visited = true; + + switch (YP_NODE_TYPE(node)) { + <%- nodes.each do |node| -%> + <%- if node.params.any? { |param| [NodeParam, OptionalNodeParam, NodeListParam].include?(param.class) } -%> +#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>" + case <%= node.type %>: { + yp_<%= node.human %>_t *cast = (yp_<%= node.human %>_t *) node; + <%- node.params.each do |param| -%> + <%- case param -%> + <%- when NodeParam, OptionalNodeParam -%> + yp_node_stack_push(&node_stack, (yp_node_t *) cast-><%= param.name %>); + <%- when NodeListParam -%> + for (size_t index = 0; index < cast-><%= param.name %>.size; index++) { + yp_node_stack_push(&node_stack, (yp_node_t *) cast-><%= param.name %>.nodes[index]); + } + <%- end -%> + <%- end -%> + break; + } + <%- end -%> + <%- end -%> + default: + break; + } +#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>" + } else { + yp_node_t *node = yp_node_stack_pop(&node_stack); + + switch (YP_NODE_TYPE(node)) { + <%- nodes.each do |node| -%> +#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>" + case <%= node.type %>: { + <%- if node.params.any? { |param| ![NodeParam, OptionalNodeParam].include?(param.class) } -%> + yp_<%= node.human %>_t *cast = (yp_<%= node.human %>_t *) node; + <%- end -%> + VALUE argv[<%= node.params.length + 1 %>]; + <%- node.params.each_with_index do |param, index| -%> + + // <%= param.name %> + <%- case param -%> + <%- when NodeParam, OptionalNodeParam -%> + argv[<%= index %>] = rb_ary_pop(value_stack); + <%- when NodeListParam -%> + argv[<%= index %>] = rb_ary_new_capa(cast-><%= param.name %>.size); + for (size_t index = 0; index < cast-><%= param.name %>.size; index++) { + rb_ary_push(argv[<%= index %>], rb_ary_pop(value_stack)); + } + <%- when StringParam -%> + argv[<%= index %>] = yp_string_new(&cast-><%= param.name %>, encoding); + <%- when LocationListParam -%> + argv[<%= index %>] = rb_ary_new_capa(cast-><%= param.name %>.size); + for (size_t index = 0; index < cast-><%= param.name %>.size; index++) { + yp_location_t location = cast-><%= param.name %>.locations[index]; + rb_ary_push(argv[<%= index %>], yp_location_new(parser, location.start, location.end, source)); + } + <%- when ConstantParam -%> + argv[<%= index %>] = rb_id2sym(constants[cast-><%= param.name %> - 1]); + <%- when ConstantListParam -%> + argv[<%= index %>] = rb_ary_new_capa(cast-><%= param.name %>.size); + for (size_t index = 0; index < cast-><%= param.name %>.size; index++) { + rb_ary_push(argv[<%= index %>], rb_id2sym(constants[cast-><%= param.name %>.ids[index] - 1])); + } + <%- when LocationParam -%> + argv[<%= index %>] = yp_location_new(parser, cast-><%= param.name %>.start, cast-><%= param.name %>.end, source); + <%- when OptionalLocationParam -%> + argv[<%= index %>] = cast-><%= param.name %>.start == NULL ? Qnil : yp_location_new(parser, cast-><%= param.name %>.start, cast-><%= param.name %>.end, source); + <%- when UInt32Param -%> + argv[<%= index %>] = ULONG2NUM(cast-><%= param.name %>); + <%- when FlagsParam -%> + argv[<%= index %>] = ULONG2NUM(node->flags >> <%= COMMON_FLAGS %>); + <%- else -%> + <%- raise -%> + <%- end -%> + <%- end -%> + + // location + argv[<%= node.params.length %>] = yp_location_new(parser, node->location.start, node->location.end, source); + + rb_ary_push(value_stack, rb_class_new_instance(<%= node.params.length + 1 %>, argv, rb_cYARP<%= node.name %>)); + break; + } + <%- end -%> + default: + rb_raise(rb_eRuntimeError, "unknown node type: %d", YP_NODE_TYPE(node)); + } + } + } + + VALUE result = rb_ary_pop(value_stack); + free(constants); + return result; +} + +void +Init_yarp_api_node(void) { + <%- nodes.each do |node| -%> + rb_cYARP<%= node.name %> = rb_define_class_under(rb_cYARP, "<%= node.name %>", rb_cYARPNode); + <%- end -%> +} |