grammar JSON::PIR is TGE::Grammar;

transform result (ROOT) {
    .local pmc pir
    .local string result

    $S0 = tree.'get'('pir', node, 'value')

    pir = new 'CodeString'
    pir.'emit'('.sub anon :anon')
    pir.'emit'($S0)
    result = node['ret']
    pir.'emit'('    .return (%0)',result)
    pir.'emit'('.end')

   .return(pir)
}

transform pir (value) {

    .local pmc sub_node, transform_result
    .local pmc pir, result
    .local string value, type

    type = 'string'
    sub_node = node[type]
    unless null sub_node goto got_type

    type = 'number'
    sub_node = node[type]
    unless null sub_node goto got_type

    type = 'object'
    sub_node = node[type]
    unless null sub_node goto got_type

    type = 'array'
    sub_node = node[type]
    unless null sub_node goto got_type

    value = node
    if value == 'true'  goto got_true
    if value == 'false' goto got_false
    if value == 'null'  goto got_null

    .return ('') # should never reach this.

  got_type:
    pir = tree.'get'('pir', sub_node, type)
    $S0 = sub_node['ret']
    node['ret'] = $S0
    .return (pir)

  got_true:
    pir = new 'CodeString'
    result = pir.'unique'('$P')
    $S0 = node
    pir.'emit'("    %0 = new 'Boolean'", result)
    pir.'emit'('    %0 = 1', result, $S0)
    node['ret'] = result
    .return(pir)

  got_false:
    pir = new 'CodeString'
    result = pir.'unique'('$P')
    $S0 = node
    pir.'emit'("    %0 = new 'Boolean'", result)
    pir.'emit'('    %0 = 0', result, $S0)
    node['ret'] = result
    .return(pir)

  got_null:
    pir = new 'CodeString'
    result = pir.'unique'('$P')
    $S0 = node
    pir.'emit'('    null %0', result)
    node['ret'] = result
    .return(pir)
}

transform pir (object) {
    .local pmc pir
    pir = new 'CodeString'
    .local string result, child_result, key_result
    result = pir.'unique'('$P')
    pir.'emit'("    %0 = new 'Hash'", result)

    .local pmc items

    items = node['members']
    if null items goto end

    items = items[0]

    .local pmc keys
    keys  = items['string']
    items = items['value']

    .local pmc it, key_iter, child, key
    key_iter = iter keys
    it       = iter items

    # the two iters should be in lockstep as a result of the PGE grammar
loop:
    unless it goto end
    child = shift it
    $P0 = tree.'get'('pir', child, 'value')
    $S0 = $P0
    pir .= $S0
    child_result = child['ret']

    key   = shift key_iter
    $P0 = tree.'get'('pir', key, 'string')
    $S0 = $P0
    pir .= $S0
    key_result = key['ret']

    pir.'emit'('    %0[%1] = %2', result, key_result, child_result)


    goto loop
end:
    node['ret'] = result

   .return (pir)
}

transform pir (array) {
    .local pmc pir
    pir = new 'CodeString'
    .local string result, child_result
    result = pir.'unique'('$P')
    pir.'emit'("    %0 = new 'ResizablePMCArray'", result)

    .local pmc items


    items = node['elements']
    if null items goto end

    items = items['value']

    .local pmc it, child
    it = iter items
loop:
    unless it goto end
    child = shift it
    $P0 = tree.'get'('pir', child, 'value')
    $S0 = $P0
    pir .= $S0

    child_result = child['ret']
    pir.'emit'('    push %0, %1', result, child_result)
    goto loop
end:
    node['ret'] = result

   .return (pir)
}

transform pir (string) {
    .local pmc pir, result, children, it, child
    .local string tmp
    tmp = ''
    pir = new 'CodeString'
    children = node['char']
    if null children goto loop_end
    it = iter children
  loop:
    push_eh loop_end
      child = shift it
    pop_eh
    unless child goto loop_end
    $S0 = child
    $I0 = length $S0
    if $I0 == 1 goto char
    if $I0 == 2 goto escape
  unicode:
    $P1 = new 'String'
    $S1 = substr $S0, 2, 4
    $P1 = $S1
    $I0 = $P1.'to_int'(16)
    $S0 = chr $I0
    goto char
  escape:
    $P0 = get_root_global ['parrot'; 'data_json'], '$escapes'
    $S0 = $P0[$S0]
  char:
    tmp .= $S0
    goto loop
  loop_end:

    result = pir.'unique'('$P')
    $S1 = pir.'escape'(tmp)
    pir.'emit'("    %0 = new 'String'", result)
    pir.'emit'('    %0 = %1', result, $S1)
    node['ret'] = result
   .return(pir)
}

transform pir (number) {
    .local pmc pir, result
    pir = new 'CodeString'
    result = pir.'unique'('$P')
    $S0 = node
    pir.'emit'("    %0 = new 'Integer'", result)
    pir.'emit'('    %0 = %1', result, $S0)
    node['ret'] = result
   .return(pir)
}
