(tk: &mut Tokenizer, ctx: &LoadCtx)
| 90 | } |
| 91 | |
| 92 | fn parse_object(tk: &mut Tokenizer, ctx: &LoadCtx) -> Result<Handle> { |
| 93 | // `object_pairs_hook` wins over `object_hook` per CPython spec: gather (key, value) pairs and call the hook on them, skipping dict build. |
| 94 | if ctx.object_pairs_hook.is_some() { |
| 95 | return parse_object_pairs(tk, ctx); |
| 96 | } |
| 97 | let dict = Handle::new_dict()?; |
| 98 | let first = tk.next_token().map_err(to_pdk_err)?; |
| 99 | if matches!(first, Token::RBrace) { |
| 100 | return apply_object_hook(dict, ctx); |
| 101 | } |
| 102 | let mut current = first; |
| 103 | loop { |
| 104 | let key_str = match current { |
| 105 | Token::Str(s) => s, |
| 106 | _ => return Err(value_err(tk.pos(), "object key must be a string")), |
| 107 | }; |
| 108 | let key = encode(Value::Bytes(key_str.into_bytes()))?; |
| 109 | match tk.next_token().map_err(to_pdk_err)? { |
| 110 | Token::Colon => {} |
| 111 | _ => return Err(value_err(tk.pos(), "expected ':' after object key")), |
| 112 | } |
| 113 | let value = parse_value(tk, ctx)?; |
| 114 | dict.set_item(&key, &value)?; |
| 115 | match tk.next_token().map_err(to_pdk_err)? { |
| 116 | Token::Comma => current = tk.next_token().map_err(to_pdk_err)?, |
| 117 | Token::RBrace => return apply_object_hook(dict, ctx), |
| 118 | _ => return Err(value_err(tk.pos(), "expected ',' or '}' in object")), |
| 119 | } |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | fn parse_object_pairs(tk: &mut Tokenizer, ctx: &LoadCtx) -> Result<Handle> { |
| 124 | let mut pairs: Vec<(Handle, Handle)> = Vec::new(); |
no test coverage detected