摘要
使用Rust实现一个JSON解析器,这里不涉及编译原理相关知识,只需要使用几个栈就可以实现JSON格式的数据解析。
{
"name": "John Doe",
"age": 43,
"address": {
"street": "10 Downing Street",
"city": "London"
},
"phones": [
"+44 1234567",
"+44 2345678"
]
}
上面的JSON数据对应Rust的HashMap
与Vec
嵌套的数据结构,被解析后显示效果如下图所示。
解析原理
先将原始的JSON数据转换成Token集合,Token集合中每一个Token都必须是合法,因此在解析Token的时候可以对JSON的基本数据类型进行校验。
JSON是一种类似树的数据结构,JSON的根节点可以是{}
,也可以是[]
,但是{}
不可以直接包含[]
和{}
,必须是键值对的形式存在,而[]
可以直接包含{}
和[]
,如[{},{},[]]
,这个是合法JSON结构,因此这里选用[]
JSON的根节点。
利用栈来保存上下文状态。
let mut maps = Vec::new();
let mut arrays = Vec::new();
let mut keys = Vec::new();
let mut parent_node = Vec::new();
let mut symbols = Vec::new();
let mut parse_state = Vec::new();
let mut next_maybe_symbols = vec![SymbolEnum::BeginObject, SymbolEnum::BeginArray];
我们需要栈来保存上下文的状态,以此来判断该JSON数据是否是合法的JSON数据。栈保存了以下信息:
maps
与arrays
保存父节点。keys
保存当前的键,以确保键和值相互对应。parent_node
用来保存当前父节点是{}
还是[]
。symbols
是一个符号栈,用来确定{
、}
和[
、]
是否成对出现。parse_state
代表解析状态,代表当前是在解析key还是value,因为需要根据解析状态来确定下一个可能会遇见哪些Token,当解析状态为ParseKey
时,那么下一个Token必须是String
类型。next_maybe_symbols
保存了下一步可能会遇见哪些符号,如{
后面只能是String
。
{ -> string(key) }
: -> bool number string null [ { (:只能出现在{}中)
[ -> bool number string null [ { ]
, -> string(key) (在{}中)
, -> bool number string null [ { (在[]中)
bool number string null -> , ] }
} -> , } ]
] -> , } ]
代码实现
将JSON数据转换成Token集合
定义Token枚举,其中Token还包含Token所在JSON数据中行列位置,当解析出错时可以给出相应的提示。
#[derive(Clone, Debug, PartialEq)]
pub enum Token {
//row col
BeginObject(u64, u64), //{
EndObject(u64, u64), //}
Colon(u64, u64), //:
BeginArray(u64, u64), //[
EndArray(u64, u64), //]
Comma(u64, u64), //,
Null(u64, u64), //null
Boolean(u64, u64, bool),
String(u64, u64, String),
Int64(u64, u64, i64),
Float64(u64, u64, f64),
}
解析String
类型
fn parse_string(row: &mut u64, col: &mut u64, chars: &mut Chars) -> Result<Token> {
let r = *row;
let c = *col;
let mut token = String::new();
let mut prev_ch = ' ';
loop {
if let Some(ch) = chars.next() {
match ch {
'"' => {
*col += 1;
if prev_ch == '\\' {
continue;
}else {
return Ok(Token::String(r, c, token));
}
}
'\n' => {
return Err(ParseError::InvalidToken(format!("JSON's Key and Value cannot contain '\\n', at {row}:{col}")))?;
}
'\t' => {
*col += 4;
token.push(ch);
}
_ => token.push(ch),
}
prev_ch = ch;
*col += 1;
} else {
return Err(ParseError::InvalidToken(format!("String ends abnormally, at {row}:{col}.")))?;
}
}
}
解析Token集合
定义JSON值类型的枚举
#[derive(Debug)]
pub enum JsonValue {
String(String),
Int64(i64),
Float64(f64),
Boolean(bool),
Object(HashMap<String, JsonValue>),
Array(Vec<JsonValue>),
Null,
}
定义Token对应的符号枚举
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum SymbolEnum {
/// {
BeginObject,
/// }
EndObject,
/// :
Colon,
/// [
BeginArray,
/// ]
EndArray,
/// ,
Comma,
/// null
Null,
Boolean,
String,
Int64,
Float64,
}
解析Token步骤如下
这里以解析到}
为例。
symbols
栈弹出符号,判断是不是{
}
属于结束符,maps
弹出一个HashMap
,代表当前节点parent_node
栈弹出- 判断
parent_node
栈顶是Map
类型还是Array
类型,如果是Map
类型,keys
栈弹出一个key,并将第2步弹出的HashMap
添加的到maps
栈顶的HashMap
- 下一步可能遇见的符号,
, ] }
更多解析细节请查看完整代码。
实现Index、IndexMut特征
Rust支持运算符重载,JsonValue
实现Index、IndexMux后可以使用[]
来访问和修改JsonValue
let _=&json["data"]["list"][0]["url"];
json["data"]["list"][1]["url"]=JsonValue::String("http://www.abc123.com".to_string());
完整可运行代码
- Cargo.toml依赖
[package]
name = "json-parserlea"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow = "1.0.83"
thiserror = "1.0.61"
- 定义一个错误类型模块
error.rs
use thiserror::Error;
#[derive(Error,Debug)]
pub enum ParseError{
#[error("parse int error")]
ParseIntError(#[from] std::num::ParseIntError),
#[error("parse float error")]
ParseFloatError(#[from] std::num::ParseFloatError),
#[error("`{0}`")]
InvalidToken(String),
#[error("`{0}`")]
SymbolMismatch(String),
#[error("`{0}`")]
Unknown(String),
}
- 定义一个词法解析模块
lex.rs
use std::{fmt::Display, str::Chars};
use anyhow::Result;
use crate::ParseError;
#[derive(Clone, Debug, PartialEq)]
pub enum Token {
//row col
BeginObject(u64, u64), //{
EndObject(u64, u64), //}
Colon(u64, u64), //:
BeginArray(u64, u64), //[
EndArray(u64, u64), //]
Comma(u64, u64), //,
Null(u64, u64), //null
Boolean(u64, u64, bool),
String(u64, u64, String),
Int64(u64, u64, i64),
Float64(u64, u64, f64),
}
impl Display for Token {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self {
Token::BeginObject(_, _) => write!(f, "{{"),
Token::EndObject(_, _) => write!(f, "}}"),
Token::Colon(_, _) => write!(f, ":"),
Token::BeginArray(_, _) => write!(f, "["),
Token::EndArray(_, _) => write!(f, "]"),
Token::Comma(_, _) => write!(f, ","),
Token::Null(_, _) => write!(f, "null"),
Token::Boolean(_, _, v) => write!(f, "{v}"),
Token::String(_, _, v) => write!(f, "\"{v}\""),
Token::Int64(_, _, v) => write!(f, "{v}"),
Token::Float64(_, _, v) => write!(f, "{v}"),
}
}
}
pub fn parse<S: AsRef<str>>(s: S) -> Result<Vec<Token>> {
let mut token_stream = vec![];
let mut chars = s.as_ref().chars();
let mut row = 1;
let mut col = 1;
while let Some(ch) = chars.next() {
match ch {
'{' => token_stream.push(Token::BeginObject(row, col)),
'}' => token_stream.push(Token::EndObject(row, col)),
'[' => token_stream.push(Token::BeginArray(row, col)),
']' => token_stream.push(Token::EndArray(row, col)),
':' => token_stream.push(Token::Colon(row, col)),
',' => token_stream.push(Token::Comma(row, col)),
'\r' => continue,
' ' => {
col += 1;
continue;
}
'\t' => {
col += 4;
continue;
}
'\n' => {
row += 1;
col = 1;
continue;
}
'"' => {
let token = parse_string(&mut row, &mut col, &mut chars)?;
token_stream.push(token);
}
'-' | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => {
let (token, next_token) = parse_number(&mut row, &mut col, ch, &mut chars)?;
token_stream.push(token);
token_stream.push(next_token);
}
't' | 'f' => {
let token = parse_bool(&mut row, &mut col, ch, &mut chars)?;
token_stream.push(token);
}
'n' => {
let token = parse_null(&mut row, &mut col, &mut chars)?;
token_stream.push(token);
}
_ => {
return Err(ParseError::InvalidToken(format!("Invalid char '{ch}', at {row}:{col}.")))?;
}
}
col += 1;
}
Ok(token_stream)
}
fn parse_string(row: &mut u64, col: &mut u64, chars: &mut Chars) -> Result<Token> {
let r = *row;
let c = *col;
let mut token = String::new();
let mut prev_ch = ' ';
loop {
if let Some(ch) = chars.next() {
match ch {
'"' => {
*col += 1;
if prev_ch == '\\' {
continue;
}else {
return Ok(Token::String(r, c, token));
}
}
'\n' => {
return Err(ParseError::InvalidToken(format!("JSON's Key and Value cannot contain '\\n', at {row}:{col}")))?;
}
'\t' => {
*col += 4;
token.push(ch);
}
_ => token.push(ch),
}
prev_ch = ch;
*col += 1;
} else {
return Err(ParseError::InvalidToken(format!("String ends abnormally, at {row}:{col}.")))?;
}
}
}
fn parse_number(row: &mut u64, col: &mut u64, ch: char, chars: &mut Chars) -> Result<(Token, Token)> {
let mut token = String::new();
token.push(ch);
let mut is_int = true;
let mut next_token = Token::Comma(0, 0);
let mut next_parse = false;
loop {
if let Some(ch) = chars.next() {
match ch {
'0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => {
*col += 1;
token.push(ch);
}
'.' => {
*col += 1;
token.push(ch);
is_int = false;
}
' ' | '\r' => {
*col += 1;
next_parse = true;
break;
}
'\t' => {
*col += 4;
next_parse = true;
break;
}
'\n' => {
*row += 1;
*col = 1;
next_parse = true;
break;
}
'}' => {
next_token = Token::EndObject(*row, *col);
*col += 1;
break;
}
']' => {
next_token = Token::EndArray(*row, *col);
*col += 1;
break;
}
',' => {
next_token = Token::Comma(*row, *col);
*col += 1;
break;
}
_ => {
return Err(ParseError::InvalidToken(format!("Invalid char '{ch}', at {row}:{col}.")))?;
}
}
} else {
return Err(ParseError::InvalidToken(format!("Number ends abnormally, at {row}:{col}.")))?;
}
}
if next_parse {
loop {
if let Some(ch) = chars.next() {
match ch {
'}' => {
next_token = Token::EndObject(*row, *col);
*col += 1;
break;
}
']' => {
next_token = Token::EndArray(*row, *col);
*col += 1;
break;
}
',' => {
next_token = Token::Comma(*row, *col);
*col += 1;
break;
}
' ' | '\r' => {
*col += 1;
continue;
}
'\t' => {
*col += 4;
continue;
}
'\n' => {
*row += 1;
*col = 1;
continue;
}
_ => {
return Err(ParseError::InvalidToken(format!("Invalid char '{ch}', at {row}:{col}.")))?;
}
}
} else {
return Err(ParseError::InvalidToken(format!("Number ends abnormally, at {row}:{col}.")))?;
}
}
}
let token = if is_int {
match token.parse::<i64>() {
Ok(v)=>Token::Int64(*row, *col, v),
Err(e)=>{
return Err(ParseError::ParseIntError(e))?;
}
}
} else {
match token.parse::<f64>() {
Ok(v)=>Token::Float64(*row, *col, v),
Err(e)=>{
return Err(ParseError::ParseFloatError(e))?;
}
}
};
Ok((token, next_token))
}
fn parse_bool(row: &mut u64, col: &mut u64, ch: char, chars: &mut Chars) -> Result<Token> {
let r = *row;
let c = *col;
let token = if ch == 't' {
if let Some(c) = chars.next() {
if c != 'r' {
return Err(ParseError::InvalidToken(format!("Invalid char '{c}', at {row}:{col}.")))?;
}
} else {
return Err(ParseError::InvalidToken(format!("Boolean ends abnormally, at {row}:{col}.")))?;
}
if let Some(c) = chars.next() {
if c != 'u' {
return Err(ParseError::InvalidToken(format!("Invalid char '{c}', at {row}:{col}.")))?;
}
} else {
return Err(ParseError::InvalidToken(format!("Boolean ends abnormally, at {row}:{col}.")))?;
}
if let Some(c) = chars.next() {
if c != 'e' {
return Err(ParseError::InvalidToken(format!("Invalid char '{c}', at {row}:{col}.")))?;
}
} else {
return Err(ParseError::InvalidToken(format!("Boolean ends abnormally, at {row}:{col}.")))?;
}
*col += 4;
Ok(Token::Boolean(r, c, true))
} else if ch == 'f' {
if let Some(c) = chars.next() {
if c != 'a' {
return Err(ParseError::InvalidToken(format!("Invalid char '{c}', at {row}:{col}.")))?;
}
} else {
return Err(ParseError::InvalidToken(format!("Boolean ends abnormally, at {row}:{col}.")))?;
}
if let Some(c) = chars.next() {
if c != 'l' {
return Err(ParseError::InvalidToken(format!("Invalid char '{c}', at {row}:{col}.")))?;
}
} else {
return Err(ParseError::InvalidToken(format!("Boolean ends abnormally, at {row}:{col}.")))?;
}
if let Some(c) = chars.next() {
if c != 's' {
return Err(ParseError::InvalidToken(format!("Invalid char '{c}', at {row}:{col}.")))?;
}
} else {
return Err(ParseError::InvalidToken(format!("Boolean ends abnormally, at {row}:{col}.")))?;
}
if let Some(c) = chars.next() {
if c != 'e' {
return Err(ParseError::InvalidToken(format!("Invalid char '{c}', at {row}:{col}.")))?;
}
} else {
return Err(ParseError::InvalidToken(format!("Boolean ends abnormally, at {row}:{col}.")))?;
}
*col += 5;
Ok(Token::Boolean(r, c, false))
} else {
return Err(ParseError::InvalidToken(format!("Invalid char '{c}', at {row}:{col}.")))?;
};
token
}
fn parse_null(row: &mut u64, col: &mut u64, chars: &mut Chars) -> Result<Token> {
if let Some(c) = chars.next() {
if c != 'u' {
return Err(ParseError::InvalidToken(format!("Invalid char '{c}', at {row}:{col}.")))?;
}
} else {
return Err(ParseError::InvalidToken(format!("Null ends abnormally, at {row}:{col}.")))?;
}
if let Some(c) = chars.next() {
if c != 'l' {
return Err(ParseError::InvalidToken(format!("Invalid char '{c}', at {row}:{col}.")))?;
}
} else {
return Err(ParseError::InvalidToken(format!("Null ends abnormally, at {row}:{col}.")))?;
}
if let Some(c) = chars.next() {
if c != 'l' {
return Err(ParseError::InvalidToken(format!("Invalid char '{c}', at {row}:{col}.")))?;
}
} else {
return Err(ParseError::InvalidToken(format!("Null ends abnormally, at {row}:{col}.")))?;
}
let t = Token::Null(*row, *col);
*col += 4;
Ok(t)
}
- 解析Token的
lib.rs
#![allow(dead_code)]
use anyhow::Result;
use std::collections::HashMap;
use std::ops::Index;
use std::ops::IndexMut;
mod error;
pub use error::ParseError;
mod lex;
pub use lex::parse;
pub use lex::Token;
#[derive(Debug)]
pub enum JsonValue {
String(String),
Int64(i64),
Float64(f64),
Boolean(bool),
Object(HashMap<String, JsonValue>),
Array(Vec<JsonValue>),
Null,
}
#[derive(Debug)]
pub enum Json {
Object(HashMap<String, JsonValue>),
Array(Vec<JsonValue>),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ParentNode {
Map,
Array,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum State {
ParseKey,
ParseValue,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum SymbolEnum {
/// {
BeginObject,
/// }
EndObject,
/// :
Colon,
/// [
BeginArray,
/// ]
EndArray,
/// ,
Comma,
/// null
Null,
Boolean,
String,
Int64,
Float64,
}
impl Token {
fn get_symbol(&self) -> SymbolEnum {
match &self {
Token::BeginObject(_, _) => SymbolEnum::BeginObject,
Token::EndObject(_, _) => SymbolEnum::EndObject,
Token::Colon(_, _) => SymbolEnum::Colon,
Token::BeginArray(_, _) => SymbolEnum::BeginArray,
Token::EndArray(_, _) => SymbolEnum::EndArray,
Token::Comma(_, _) => SymbolEnum::Comma,
Token::Null(_, _) => SymbolEnum::Null,
Token::Boolean(_, _, _) => SymbolEnum::Boolean,
Token::String(_, _, _) => SymbolEnum::String,
Token::Int64(_, _, _) => SymbolEnum::Int64,
Token::Float64(_, _, _) => SymbolEnum::Float64,
}
}
}
// { -> string(key) }
// : -> bool number string null [ { (:只能出现在{}中)
// [ -> bool number string null [ { ]
// , -> string(key) (在{}中)
// , -> bool number string null [ { (在[]中)
// bool number string null -> , ] }
// } -> , } ]
// ] -> , } ]
pub fn parse_json(token_stream: Vec<Token>) -> Result<Json> {
let mut token_stream = token_stream.into_iter();
let mut maps = Vec::new();
let mut arrays = Vec::new();
let mut keys = Vec::new();
let mut parent_node = Vec::new();
let mut symbols = Vec::new();
let mut parse_state = Vec::new();
let mut next_maybe_symbols = vec![SymbolEnum::BeginObject, SymbolEnum::BeginArray];
parent_node.push(ParentNode::Array);
arrays.push(Vec::new());
while let Some(token) = token_stream.next() {
let symbol = token.get_symbol();
if !next_maybe_symbols.contains(&symbol) {
let (row, col) = get_row_col(&token);
let content = format!(
"The following symbols may be required `{next_maybe_symbols:?}`,
but provided is `{symbol:?}`, at {row}:{col}"
);
return Err(ParseError::SymbolMismatch(content))?;
}
next_maybe_symbols.clear();
match token {
Token::BeginObject(_, _) => {
symbols.push(symbol);
maps.push(HashMap::new());
parent_node.push(ParentNode::Map);
parse_state.push(State::ParseKey);
next_maybe_symbols.push(SymbolEnum::String);
next_maybe_symbols.push(SymbolEnum::EndObject);
}
Token::EndObject(row, col) => {
if symbols.pop() != Some(SymbolEnum::BeginObject) {
let content = format!("Missing corresponding symbol, at {row}:{col}");
return Err(ParseError::SymbolMismatch(content))?;
}
let current_map = maps.pop().unwrap();
let _ = parent_node.pop().unwrap();
if current_map.is_empty() {
assert_eq!(parse_state.pop(), Some(State::ParseKey));
}
match parent_node.last().unwrap() {
ParentNode::Map => {
assert_eq!(parse_state.pop(), Some(State::ParseValue));
assert_eq!(parse_state.pop(), Some(State::ParseKey));
let k = keys.pop().unwrap();
maps.last_mut()
.unwrap()
.insert(k, JsonValue::Object(current_map));
}
ParentNode::Array => {
arrays
.last_mut()
.unwrap()
.push(JsonValue::Object(current_map));
}
}
next_maybe_symbols.push(SymbolEnum::Comma);
next_maybe_symbols.push(SymbolEnum::EndArray);
next_maybe_symbols.push(SymbolEnum::EndObject);
}
Token::BeginArray(_, _) => {
symbols.push(symbol);
arrays.push(Vec::new());
parent_node.push(ParentNode::Array);
next_maybe_symbols.push(SymbolEnum::String);
next_maybe_symbols.push(SymbolEnum::Int64);
next_maybe_symbols.push(SymbolEnum::Float64);
next_maybe_symbols.push(SymbolEnum::Boolean);
next_maybe_symbols.push(SymbolEnum::Null);
next_maybe_symbols.push(SymbolEnum::BeginArray);
next_maybe_symbols.push(SymbolEnum::EndArray);
next_maybe_symbols.push(SymbolEnum::BeginObject);
}
Token::EndArray(row, col) => {
if symbols.pop() != Some(SymbolEnum::BeginArray) {
let content = format!("Missing corresponding symbol, at {row}:{col}");
return Err(ParseError::SymbolMismatch(content))?;
}
let current_list = arrays.pop().unwrap();
let _ = parent_node.pop().unwrap();
match parent_node.last().unwrap() {
ParentNode::Map => {
assert_eq!(parse_state.pop(), Some(State::ParseValue));
assert_eq!(parse_state.pop(), Some(State::ParseKey));
let k = keys.pop().unwrap();
maps.last_mut()
.unwrap()
.insert(k, JsonValue::Array(current_list));
}
ParentNode::Array => {
arrays
.last_mut()
.unwrap()
.push(JsonValue::Array(current_list));
}
}
next_maybe_symbols.push(SymbolEnum::Comma);
next_maybe_symbols.push(SymbolEnum::EndArray);
next_maybe_symbols.push(SymbolEnum::EndObject);
}
Token::Comma(_, _) => match parent_node.last().unwrap() {
ParentNode::Map => {
parse_state.push(State::ParseKey);
next_maybe_symbols.push(SymbolEnum::String);
}
ParentNode::Array => {
next_maybe_symbols.push(SymbolEnum::String);
next_maybe_symbols.push(SymbolEnum::Int64);
next_maybe_symbols.push(SymbolEnum::Float64);
next_maybe_symbols.push(SymbolEnum::Boolean);
next_maybe_symbols.push(SymbolEnum::Null);
next_maybe_symbols.push(SymbolEnum::BeginArray);
next_maybe_symbols.push(SymbolEnum::BeginObject);
}
},
Token::String(_, _, string) => match parent_node.last().unwrap() {
ParentNode::Map => match parse_state.last().unwrap() {
State::ParseKey => {
keys.push(string);
next_maybe_symbols.push(SymbolEnum::Colon);
}
State::ParseValue => {
let key = keys.pop().unwrap();
let value = JsonValue::String(string);
maps.last_mut().unwrap().insert(key, value);
assert_eq!(parse_state.pop(), Some(State::ParseValue));
assert_eq!(parse_state.pop(), Some(State::ParseKey));
next_maybe_symbols.push(SymbolEnum::Comma);
next_maybe_symbols.push(SymbolEnum::EndObject);
}
},
ParentNode::Array => {
let value = JsonValue::String(string);
arrays.last_mut().unwrap().push(value);
next_maybe_symbols.push(SymbolEnum::Comma);
next_maybe_symbols.push(SymbolEnum::EndArray);
}
},
Token::Colon(_, _) => {
parse_state.push(State::ParseValue);
next_maybe_symbols.push(SymbolEnum::String);
next_maybe_symbols.push(SymbolEnum::Int64);
next_maybe_symbols.push(SymbolEnum::Float64);
next_maybe_symbols.push(SymbolEnum::Boolean);
next_maybe_symbols.push(SymbolEnum::Null);
next_maybe_symbols.push(SymbolEnum::BeginArray);
next_maybe_symbols.push(SymbolEnum::BeginObject);
}
Token::Int64(_, _, int64) => match parent_node.last().unwrap() {
ParentNode::Map => {
let key = keys.pop().unwrap();
let value = JsonValue::Int64(int64);
maps.last_mut().unwrap().insert(key, value);
assert_eq!(parse_state.pop(), Some(State::ParseValue));
assert_eq!(parse_state.pop(), Some(State::ParseKey));
next_maybe_symbols.push(SymbolEnum::Comma);
next_maybe_symbols.push(SymbolEnum::EndObject);
}
ParentNode::Array => {
let value = JsonValue::Int64(int64);
arrays.last_mut().unwrap().push(value);
next_maybe_symbols.push(SymbolEnum::Comma);
next_maybe_symbols.push(SymbolEnum::EndArray);
}
},
Token::Float64(_, _, float64) => match parent_node.last().unwrap() {
ParentNode::Map => {
let key = keys.pop().unwrap();
let value = JsonValue::Float64(float64);
maps.last_mut().unwrap().insert(key, value);
assert_eq!(parse_state.pop(), Some(State::ParseValue));
assert_eq!(parse_state.pop(), Some(State::ParseKey));
next_maybe_symbols.push(SymbolEnum::Comma);
next_maybe_symbols.push(SymbolEnum::EndObject);
}
ParentNode::Array => {
let value = JsonValue::Float64(float64);
arrays.last_mut().unwrap().push(value);
next_maybe_symbols.push(SymbolEnum::Comma);
next_maybe_symbols.push(SymbolEnum::EndArray);
}
},
Token::Boolean(_, _, boolean) => match parent_node.last().unwrap() {
ParentNode::Map => {
let key = keys.pop().unwrap();
let value = JsonValue::Boolean(boolean);
maps.last_mut().unwrap().insert(key, value);
assert_eq!(parse_state.pop(), Some(State::ParseValue));
assert_eq!(parse_state.pop(), Some(State::ParseKey));
next_maybe_symbols.push(SymbolEnum::Comma);
next_maybe_symbols.push(SymbolEnum::EndObject);
}
ParentNode::Array => {
let value = JsonValue::Boolean(boolean);
arrays.last_mut().unwrap().push(value);
next_maybe_symbols.push(SymbolEnum::Comma);
next_maybe_symbols.push(SymbolEnum::EndArray);
}
},
Token::Null(_, _) => match parent_node.last().unwrap() {
ParentNode::Map => {
let key = keys.pop().unwrap();
let value = JsonValue::Null;
maps.last_mut().unwrap().insert(key, value);
assert_eq!(parse_state.pop(), Some(State::ParseValue));
assert_eq!(parse_state.pop(), Some(State::ParseKey));
next_maybe_symbols.push(SymbolEnum::Comma);
next_maybe_symbols.push(SymbolEnum::EndObject);
}
ParentNode::Array => {
let value = JsonValue::Null;
arrays.last_mut().unwrap().push(value);
next_maybe_symbols.push(SymbolEnum::Comma);
next_maybe_symbols.push(SymbolEnum::EndArray);
}
},
}
}
let json = arrays.pop().unwrap().pop().unwrap();
match json {
JsonValue::Object(m) => Ok(Json::Object(m)),
JsonValue::Array(l) => Ok(Json::Array(l)),
_ => unreachable!(),
}
}
#[inline]
fn get_row_col(token: &Token) -> (u64, u64) {
match token {
Token::BeginObject(r, c) => (*r, *c),
Token::EndObject(r, c) => (*r, *c),
Token::Colon(r, c) => (*r, *c),
Token::BeginArray(r, c) => (*r, *c),
Token::EndArray(r, c) => (*r, *c),
Token::Comma(r, c) => (*r, *c),
Token::Null(r, c) => (*r, *c),
Token::Boolean(r, c, _) => (*r, *c),
Token::String(r, c, _) => (*r, *c),
Token::Int64(r, c, _) => (*r, *c),
Token::Float64(r, c, _) => (*r, *c),
}
}
impl<'a> Index<&'a str> for Json {
type Output = JsonValue;
fn index(&self, index: &str) -> &Self::Output {
match self {
Json::Array(_) => {
panic!("This operation is not supported.")
}
Json::Object(value) => &value[index],
}
}
}
impl Index<usize> for Json {
type Output = JsonValue;
fn index(&self, index: usize) -> &Self::Output {
match self {
Json::Array(value) => &value[index],
Json::Object(_) => {
panic!("This operation is not supported.")
}
}
}
}
impl<'a> Index<&'a str> for JsonValue {
type Output = JsonValue;
fn index(&self, index: &str) -> &Self::Output {
match self {
JsonValue::Object(value) => &value[index],
_ => {
panic!("This operation is not supported.")
}
}
}
}
impl Index<usize> for JsonValue {
type Output = JsonValue;
fn index(&self, index: usize) -> &Self::Output {
match self {
JsonValue::Array(value) => &value[index],
_ => {
panic!("This operation is not supported.")
}
}
}
}
impl<'a> IndexMut<&'a str> for Json {
fn index_mut(&mut self, index: &str) -> &mut Self::Output {
match self {
Json::Array(_) => {
panic!("This operation is not supported.")
}
Json::Object(value) => value.get_mut(index).expect("no entry found for key"),
}
}
}
impl IndexMut<usize> for Json {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
match self {
Json::Array(value) => value.get_mut(index).expect("Index out of bounds."),
Json::Object(_) => {
panic!("This operation is not supported.")
}
}
}
}
impl<'a> IndexMut<&'a str> for JsonValue {
fn index_mut(&mut self, index: &str) -> &mut Self::Output {
match self {
JsonValue::Object(value) => value.get_mut(index).expect("no entry found for key"),
_ => {
panic!("This operation is not supported.")
}
}
}
}
impl IndexMut<usize> for JsonValue {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
match self {
JsonValue::Array(value) => value.get_mut(index).expect("Index out of bounds."),
_ => {
panic!("This operation is not supported.")
}
}
}
}
效果演示
use json_parserlea::{parse, Json, JsonValue};
use std::fs;
fn main() {
let json = fs::read_to_string("./jsons/images.json").unwrap();
let tokens = parse(json.as_str()).unwrap();
let mut json = json_parserlea::parse_json(tokens).unwrap();
println!("{:#?}", json);
json["data"]["list"][1]["url"]=JsonValue::String("http://www.abc123.com".to_string());
let j=&json["data"]["list"][0]["url"];
println!("{:#?}",j);
match json {
Json::Array(_) => unreachable!(),
Json::Object(map) => match &map["data"] {
JsonValue::Object(map) => match &map["list"] {
JsonValue::Array(list) => {
let urls = list
.iter()
.map(|value| match value {
JsonValue::Object(obj) => &obj["url"],
_ => unreachable!(),
})
.map(|value| match value {
JsonValue::String(v) => v,
_ => unreachable!(),
})
.collect::<Vec<&String>>();
println!("{:#?}", urls);
}
_ => unreachable!(),
},
_ => unreachable!(),
},
}
}