Search code examples
c++duktape

How to parse recursive json data in duktape?


I am trying to parse an recursive data structure with duktape and seem to have an error somewhere. Since i am new to the duktape library and the examples are not clear on this situation, i thought i could ask the crowd.

The data:

{
  "type": "window",
  "children": [
    {
      "type": "button"
    },
    {
      "type": "button"
    }
  ]
}

With the functions used to parse it:

void parse_config() {
  duk_context* context = duk_create_heap_default();
  std::cout << "duk_create_heap_default" << std::endl;
  duk_push_string(context, input.c_str());
  std::cout << "duk_push_string" << std::endl;
  duk_json_decode(context, 0);
  std::cout << "duk_json_decode" << std::endl;
  parse_widget(context);
}

void parse_widget(duk_context* context) {
  duk_get_prop_string(context, 0, "type");
  std::cout << "duk_get_prop_string" << std::endl;
  auto type = duk_get_string(context, 1);
  std::cout << "duk_get_string" << std::endl;
  duk_pop(context);
  std::cout << "duk_pop" << std::endl;
  std::cout << "type: " << type << std::endl;
  if (duk_has_prop_string(context, 0, "children")) {
    std::cout << "duk_has_prop_string" << std::endl;
    parse_children(context);
  } else {
    std::cout << "duk_has_prop_string" << std::endl;
    std::cout << "no children" << std::endl;
  }
}

void parse_children(duk_context* context) {
  duk_get_prop_string(context, 0, "children");
  std::cout << "duk_get_prop_string" << std::endl;
  if (duk_is_array(context, 1)) {
    std::cout << "duk_is_array" << std::endl;
    duk_enum(context, 1, 0);
    std::cout << "duk_enum" << std::endl;
    while (duk_next(context, 2, 0)) {
      std::cout << "duk_next" << std::endl;
      std::cout << "parse child" << std::endl;
      parse_widget(context);
    }
  }
}

With this version i get the output:

$ ./programm
duk_create_heap_default
duk_push_string
duk_json_decode
duk_get_prop_string
duk_get_string
duk_pop
type: window
duk_has_prop_string
duk_get_prop_string
duk_is_array
duk_enum
duk_next
parse child
duk_get_prop_string
duk_get_string
duk_pop
type: $

The correct output should of course be:

duk_create_heap_default
duk_push_string
duk_json_decode
duk_get_prop_string
duk_get_string
duk_pop
type: window
duk_has_prop_string
duk_get_prop_string
duk_is_array
duk_enum
duk_next
parse child
duk_get_prop_string
duk_get_string
duk_pop
type: button
duk_has_prop_string
no children
duk_next
parse child
duk_get_prop_string
duk_get_string
duk_pop
type: button
duk_has_prop_string
no children

So the question remains: where is my error in parsing the data?


Solution

  • There are two problems I can see:

    • You're using value stack indices 0 and 1 in parse_widget/parse_children which will be incorrect once you recurse. Note that the stack index 0 does not change when you do normal C function calls (but does change when you call into a native/Ecmascript function using e.g. duk_call()). You should use negative indices to refer to items relative to stack top; you could also use non-negative indices but keep track of a base index to the current widget being processed.

    • There's a duk_pop() missing for the children array, as well as for the enumerated key and value in the duk_next() loop.