{
// Package json parses JSON as defined by [1].
//
// BUGS: the escaped forward solidus (`\/`) is not currently handled.
//
// [1]: http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
package json

func toIfaceSlice(v interface{}) []interface{} {
    if v == nil {
        return nil
    }
    return v.([]interface{})
}
}

JSON ← _ vals:Value+ EOF {
    valsSl := toIfaceSlice(vals)
    switch len(valsSl) {
    case 0:
        return nil, nil
    case 1:
        return valsSl[0], nil
    default:
        return valsSl, nil
    }
}

Value ← val:( Object / Array / Number / String / Bool / Null ) _ {
    return val, nil
}

Object ← '{' _ vals:( String _ ':' _ Value ( ',' _ String _ ':' _ Value )* )? '}' {
    res := make(map[string]interface{})
    valsSl := toIfaceSlice(vals)
    if len(valsSl) == 0 {
        return res, nil
    }
    res[valsSl[0].(string)] = valsSl[4]
    restSl := toIfaceSlice(valsSl[5])
    for _, v := range restSl {
        vSl := toIfaceSlice(v)
        res[vSl[2].(string)] = vSl[6]
    }
    return res, nil
}

Array ← '[' _ vals:( Value ( ',' _ Value )* )? ']' {
    valsSl := toIfaceSlice(vals)
    if len(valsSl) == 0 {
        return []interface{}{}, nil
    }
    res := []interface{}{valsSl[0]}
    restSl := toIfaceSlice(valsSl[1])
    for _, v := range restSl {
        vSl := toIfaceSlice(v)
        res = append(res, vSl[2])
    }
    return res, nil
}

Number ← '-'? Integer ( '.' DecimalDigit+ )? Exponent? {
    // JSON numbers have the same syntax as Go's, and are parseable using
    // strconv.
    return strconv.ParseFloat(string(c.text), 64)
}

Integer ← '0' / NonZeroDecimalDigit DecimalDigit*

Exponent ← 'e'i [+-]? DecimalDigit+

String ← '"' ( !EscapedChar . / '\\' EscapeSequence )* '"' {
    // TODO : the forward slash (solidus) is not a valid escape in Go, it will
    // fail if there's one in the string
    return strconv.Unquote(string(c.text))
}

EscapedChar ← [\x00-\x1f"\\]

EscapeSequence ← SingleCharEscape / UnicodeEscape

SingleCharEscape ← ["\\/bfnrt]

UnicodeEscape ← 'u' HexDigit HexDigit HexDigit HexDigit

DecimalDigit ← [0-9]

NonZeroDecimalDigit ← [1-9]

HexDigit ← [0-9a-f]i

Bool ← "true" { return true, nil } / "false" { return false, nil }

Null ← "null" { return nil, nil }

_ "whitespace" ← [ \t\r\n]*

EOF ← !.
