aboutsummaryrefslogtreecommitdiffstats
path: root/yarp/templates/ext/yarp/api_node.c.erb
diff options
context:
space:
mode:
Diffstat (limited to 'yarp/templates/ext/yarp/api_node.c.erb')
-rw-r--r--yarp/templates/ext/yarp/api_node.c.erb204
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 -%>
+}