grammar JSON::PIR is TGE::Grammar;

transform result (ROOT) {
    .local pmc pir
    .local string result
 
    $S0 = tree.'get'('pir', node, 'thing')

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

   .return(pir)
} 

transform pir (thing) {

    .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 'PGE::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 'PGE::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 'PGE::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 'PGE::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['thing']

    .local pmc iter, key_iter, child, key
    key_iter = new .Iterator, keys
    iter     = new .Iterator, items

    # the two iters should be in lockstep as a result of the PGE grammar
loop:
    unless iter goto end
    child = shift iter
    $P0 = tree.'get'('pir', child, 'thing')
    $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 'PGE::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['thing']

    .local pmc iter, child
    iter = new .Iterator, items
loop:
    unless iter goto end
    child = shift iter
    $P0 = tree.'get'('pir', child, 'thing')
    $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, iter, child
    .local string tmp
    tmp = ''
    pir = new 'PGE::CodeString'
    children = node['char']
    if null children goto loop_end
    iter = new .Iterator, children 
  loop:
    push_eh loop_end
      child = shift iter
    clear_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 [ '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 'PGE::CodeString'
    result = pir.unique('$P')
    $S0 = node
    pir.emit('    %0 = new .Integer', result)
    pir.emit('    %0 = %1', result, $S0)
    node['ret'] = result
   .return(pir)
}
