diff --git a/ext/mini_racer_extension/mini_racer_extension.c b/ext/mini_racer_extension/mini_racer_extension.c index 12a27ff..42aecce 100644 --- a/ext/mini_racer_extension/mini_racer_extension.c +++ b/ext/mini_racer_extension/mini_racer_extension.c @@ -171,13 +171,14 @@ static void *rendezvous_callback(void *arg); typedef struct State { VALUE a, b; + uint8_t verbatim_keys:1; } State; // note: must be stack-allocated or VALUEs won't be visible to ruby's GC typedef struct DesCtx { State *tos; - VALUE refs; // array + VALUE refs; // object refs array uint8_t transcode_latin1:1; char err[64]; State stack[512]; @@ -199,7 +200,7 @@ static void DesCtx_init(DesCtx *c) { c->tos = c->stack; c->refs = rb_ary_new(); - *c->tos = (State){Qundef, Qundef}; + *c->tos = (State){Qundef, Qundef, /*verbatim_keys*/0}; *c->err = '\0'; c->transcode_latin1 = 1; // convert to utf8 } @@ -220,7 +221,8 @@ static void put(DesCtx *c, VALUE v) if (*b == Qundef) { *b = v; } else { - *b = rb_funcall(*b, rb_intern("to_s"), 0); + if (!c->tos->verbatim_keys) + *b = rb_funcall(*b, rb_intern("to_s"), 0); rb_hash_aset(*a, *b, v); *b = Qundef; } @@ -242,7 +244,7 @@ static void push(DesCtx *c, VALUE v) snprintf(c->err, sizeof(c->err), "stack overflow"); return; } - *++c->tos = (State){v, Qundef}; + *++c->tos = (State){v, Qundef, /*verbatim_keys*/0}; rb_ary_push(c->refs, v); } @@ -426,6 +428,20 @@ static void des_object_end(void *arg) pop(arg); } +static void des_map_begin(void *arg) +{ + DesCtx *c; + + c = arg; + push(c, rb_hash_new()); + c->tos->verbatim_keys = 1; // don't stringify or intern keys +} + +static void des_map_end(void *arg) +{ + pop(arg); +} + static void des_object_ref(void *arg, uint32_t id) { DesCtx *c; diff --git a/ext/mini_racer_extension/serde.c b/ext/mini_racer_extension/serde.c index 3c51ce2..65aab21 100644 --- a/ext/mini_racer_extension/serde.c +++ b/ext/mini_racer_extension/serde.c @@ -31,6 +31,8 @@ static void des_named_props_begin(void *arg); static void des_named_props_end(void *arg); static void des_object_begin(void *arg); static void des_object_end(void *arg); +static void des_map_begin(void *arg); +static void des_map_end(void *arg); static void des_object_ref(void *arg, uint32_t id); // des_error_begin: followed by des_object_begin + des_object_end calls static void des_error_begin(void *arg); @@ -642,7 +644,7 @@ static int des1(char (*err)[64], const uint8_t **p, const uint8_t *pe, des_object_end(arg); break; case ';': // Map - des_object_begin(arg); + des_map_begin(arg); for (u = 0; /*empty*/; u++) { if (*p >= pe) goto too_short; @@ -658,7 +660,7 @@ static int des1(char (*err)[64], const uint8_t **p, const uint8_t *pe, goto bad_varint; if (t != 2*u) return bail(err, "map element count mismatch"); - des_object_end(arg); + des_map_end(arg); break; case '\'': // Set des_array_begin(arg); diff --git a/test/mini_racer_test.rb b/test/mini_racer_test.rb index 5e2d8b9..2a894c8 100644 --- a/test/mini_racer_test.rb +++ b/test/mini_racer_test.rb @@ -1097,7 +1097,7 @@ def test_function_property } else expected = { - "m" => {"1" => 2, "3" => 4}, # TODO(bnoordhuis) retain numeric keys + "m" => {1 => 2, 3 => 4}, "s" => [5, 7, 11, 13], "x" => 42, }