module JsonParsing { 
 
  import { ../Json; ../JsonScanning; } 
 
  // JsonParser 
 
  pub mut struct JsonParser { 
    scanner: JsonScanner; 
  } 
 
  pub constructor(text : string) : JsonParser => { 
    return JsonParser(JsonScanner(text)); 
  } 
 
  pub parseValue(this : JsonParser) : JsonValue => { 
    let token = this.scanner.scan(); 
    return this.parseToken(token); 
  } 
 
  parseToken(this : JsonParser, token : JsonToken) : JsonValue => { 
    match (token) { 
      JsonNullToken             => none; 
      JsonNumberToken(@val)     => val; 
      JsonBoolToken(@val)       => val; 
      JsonStringToken(@val)     => val; 
      JsonLeftBraceToken        => this.parseObject(); 
      JsonLeftBracketToken      => this.parseArray(); 
      _                         => throw JsonUnexpectedToken(token); 
    } 
  } 
 
  parseArray(this : JsonParser) : JsonArray => { 
    let array : mut JsonValue[] = []; 
    loop { 
      let token = this.scanner.scan(); 
      if (token == JsonRightBracketToken) { 
        break; 
      } 
      array.append(this.parseToken(token)); 
    } 
    return array.take(); 
  } 
 
  parseObject(this : JsonParser) : JsonObject => { 
    let object : mut JsonMap = {}; 
    loop { 
      let token = this.scanner.scan(); 
      if (token == JsonRightBraceToken) { 
        break; 
      } 
      let field = token.verify{JsonStringToken}().val; 
      token = this.scanner.scan(); 
      token.verify{JsonColonToken}(); 
      token = this.scan.scan(); 
      let value = parseToken(token); 
      object[field] = value; 
    } 
    return object.take(); 
  } 
 
  // Helpers 
 
  verify{T}(token : JsonToken) : T => { 
    if (!(token is T)) { 
      throw JsonUnexpectedToken(token); 
    } 
    return token::T; 
  } 
}