#include "../libs/tree-sitter-ruby/bindings/c/tree-sitter-ruby.h"
#include "../libs/tree-sitter/lib/include/tree_sitter/api.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static void die(const char *msg) {
  fprintf(stderr, "error: %s\n", msg);
  exit(1);
}

static char *read_stdin(size_t *out_len) {
  size_t cap = 4096, len = 0;
  char *buf = (char *)malloc(cap);
  if (!buf)
    die("malloc failed");
  size_t n;
  while (!feof(stdin)) {
    if (cap - len < 2048) {
      cap *= 2;
      char *tmp = (char *)realloc(buf, cap);
      if (!tmp) {
        free(buf);
        die("realloc failed");
      }
      buf = tmp;
    }
    n = fread(buf + len, 1, cap - len, stdin);
    len += n;
  }
  // ensure NUL-terminated for convenience
  if (len == cap) {
    char *tmp = (char *)realloc(buf, cap + 1);
    if (!tmp) {
      free(buf);
      die("realloc term failed");
    }
    buf = tmp;
  }
  buf[len] = '\0';
  if (out_len)
    *out_len = len;
  return buf;
}

static void walk(TSNode node, int depth) {
  uint16_t sym = ts_node_symbol(node);
  const char *type = ts_node_type(node);
  for (int i = 0; i < depth; i++)
    putchar(' ');
  uint32_t n = ts_node_child_count(node);
  printf("#define SYM_%s %u\n", type, sym);
  for (uint32_t i = 0; i < n; i++) {
    TSNode child = ts_node_child(node, i);
    walk(child, depth + 2);
  }
}

int main(void) {
  size_t len = 0;
  char *src = read_stdin(&len);
  if (len == 0) {
    fprintf(stderr,
            "No input on stdin. Paste some Ruby code and press Ctrl-D.\n");
    free(src);
    return 1;
  }

  TSParser *parser = ts_parser_new();
  if (!parser) {
    free(src);
    die("ts_parser_new failed");
  }

  if (!ts_parser_set_language(parser, tree_sitter_ruby())) {
    ts_parser_delete(parser);
    free(src);
    die("ts_parser_set_language failed (is tree-sitter-ruby linked?)");
  }

  TSTree *tree = ts_parser_parse_string(parser, NULL, src, (uint32_t)len);
  if (!tree) {
    ts_parser_delete(parser);
    free(src);
    die("parse failed");
  }

  TSNode root = ts_tree_root_node(tree);
  walk(root, 0);

  ts_tree_delete(tree);
  ts_parser_delete(parser);
  free(src);
  return 0;
}
