mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-06-06 21:08:48 +08:00
Add support for old version of ast files
This commit is contained in:
@@ -34,12 +34,20 @@ impl LenChecker {
|
||||
}
|
||||
}
|
||||
Value::KeyVal((k, v)) => {
|
||||
self.current_len += k.as_bytes().len()
|
||||
+ if lua_key_contains_need_escape(k) {
|
||||
7
|
||||
} else {
|
||||
3
|
||||
};
|
||||
if let Some(key) = k.as_str() {
|
||||
self.current_len += key.as_bytes().len()
|
||||
+ if lua_key_contains_need_escape(key) {
|
||||
7
|
||||
} else {
|
||||
3
|
||||
};
|
||||
} else {
|
||||
self.current_len += 1; // for '['
|
||||
if !self.check(k) {
|
||||
return false;
|
||||
}
|
||||
self.current_len += 4; // for '] = '
|
||||
}
|
||||
if !self.check(v) {
|
||||
return false;
|
||||
}
|
||||
@@ -106,8 +114,10 @@ impl<'a> Dumper<'a> {
|
||||
|
||||
pub fn dump(mut self, ast: &AstFile) -> std::io::Result<()> {
|
||||
if self.indent.is_none() {
|
||||
self.writer.write(b"astver=")?;
|
||||
self.dump_f64(&ast.astver)?;
|
||||
if let Some(astver) = ast.astver {
|
||||
self.writer.write(b"astver=")?;
|
||||
self.dump_f64(&astver)?;
|
||||
}
|
||||
if let Some(astname) = &ast.astname {
|
||||
self.writer.write(b"\nastname = ")?;
|
||||
if lua_str_contains_need_escape(astname) {
|
||||
@@ -123,8 +133,10 @@ impl<'a> Dumper<'a> {
|
||||
self.writer.write(b"\nast=")?;
|
||||
self.dump_value(&ast.ast)?;
|
||||
} else {
|
||||
self.writer.write(b"astver = ")?;
|
||||
self.dump_f64(&ast.astver)?;
|
||||
if let Some(astver) = ast.astver {
|
||||
self.writer.write(b"astver = ")?;
|
||||
self.dump_f64(&astver)?;
|
||||
}
|
||||
if let Some(astname) = &ast.astname {
|
||||
self.writer.write(b"\nastname = ")?;
|
||||
if lua_str_contains_need_escape(&astname) {
|
||||
@@ -162,13 +174,19 @@ impl<'a> Dumper<'a> {
|
||||
}
|
||||
}
|
||||
Value::KeyVal((k, v)) => {
|
||||
if lua_key_contains_need_escape(k) {
|
||||
self.writer.write(b"[\"")?;
|
||||
self.writer.write(k.as_bytes())?;
|
||||
self.writer.write(b"\"]=")?;
|
||||
if let Some(k) = k.as_str() {
|
||||
if lua_key_contains_need_escape(k) {
|
||||
self.writer.write(b"[\"")?;
|
||||
self.writer.write(k.as_bytes())?;
|
||||
self.writer.write(b"\"]=")?;
|
||||
} else {
|
||||
self.writer.write(k.as_bytes())?;
|
||||
self.writer.write(b"=")?;
|
||||
}
|
||||
} else {
|
||||
self.writer.write(k.as_bytes())?;
|
||||
self.writer.write(b"=")?;
|
||||
self.writer.write(b"[")?;
|
||||
self.dump_value(k)?;
|
||||
self.writer.write(b"]=")?;
|
||||
}
|
||||
self.dump_value(v)?;
|
||||
}
|
||||
@@ -202,17 +220,25 @@ impl<'a> Dumper<'a> {
|
||||
}
|
||||
}
|
||||
Value::KeyVal((k, v)) => {
|
||||
let bytes = k.as_bytes();
|
||||
if lua_key_contains_need_escape(k) {
|
||||
self.writer.write(b"[\"")?;
|
||||
self.writer.write(bytes)?;
|
||||
self.writer.write(b"\"] = ")?;
|
||||
self.current_line_width += bytes.len() + 7;
|
||||
if let Some(k) = k.as_str() {
|
||||
let bytes = k.as_bytes();
|
||||
if lua_key_contains_need_escape(k) {
|
||||
self.writer.write(b"[\"")?;
|
||||
self.writer.write(bytes)?;
|
||||
self.writer.write(b"\"] = ")?;
|
||||
self.current_line_width += bytes.len() + 7;
|
||||
} else {
|
||||
self.writer.write(bytes)?;
|
||||
self.writer.write(b" = ")?;
|
||||
self.current_line_width += bytes.len() + 3;
|
||||
}
|
||||
} else {
|
||||
self.writer.write(bytes)?;
|
||||
self.writer.write(b" = ")?;
|
||||
self.current_line_width += bytes.len() + 3;
|
||||
}
|
||||
self.writer.write(b"[")?;
|
||||
self.current_line_width += 1;
|
||||
self.dump_value(k)?;
|
||||
self.writer.write(b"] = ")?;
|
||||
self.current_line_width += 4; // for '] = '
|
||||
};
|
||||
if v.is_array() {
|
||||
let tlen = self.current_line_width + self.current_indent;
|
||||
if tlen < self.max_line_width {
|
||||
@@ -280,14 +306,20 @@ impl<'a> Dumper<'a> {
|
||||
}
|
||||
}
|
||||
Value::KeyVal((k, v)) => {
|
||||
if lua_key_contains_need_escape(k) {
|
||||
self.writer.write(b"[\"")?;
|
||||
self.writer.write(k.as_bytes())?;
|
||||
self.writer.write(b"\"]=")?;
|
||||
if let Some(k) = k.as_str() {
|
||||
if lua_key_contains_need_escape(k) {
|
||||
self.writer.write(b"[\"")?;
|
||||
self.writer.write(k.as_bytes())?;
|
||||
self.writer.write(b"\"]=")?;
|
||||
} else {
|
||||
self.writer.write(k.as_bytes())?;
|
||||
self.writer.write(b"=")?;
|
||||
}
|
||||
} else {
|
||||
self.writer.write(k.as_bytes())?;
|
||||
self.writer.write(b"=")?;
|
||||
}
|
||||
self.writer.write(b"[")?;
|
||||
self.dump_value_in_one(k)?;
|
||||
self.writer.write(b"]=")?;
|
||||
};
|
||||
self.dump_value_in_one(v)?;
|
||||
}
|
||||
Value::Array(arr) => {
|
||||
|
||||
@@ -89,11 +89,136 @@ impl Script for AstScript {
|
||||
fn extract_messages(&self) -> Result<Vec<Message>> {
|
||||
let mut messages = Vec::new();
|
||||
let ast = &self.ast.ast;
|
||||
let mut lang: Option<&str> = self.lang.as_ref().map(|s| s.as_str());
|
||||
// old version
|
||||
if ast["label"]["top"]["block"].is_null() && ast["text"].is_array() {
|
||||
let text = &ast["text"];
|
||||
let mut text_index = 1i64;
|
||||
for block in ast.members() {
|
||||
if block.is_array() {
|
||||
let savetitle = &block[Key("savetitle")];
|
||||
if savetitle.is_array() {
|
||||
if let Some(lang) = lang {
|
||||
if let Some(title) = savetitle[lang].as_str() {
|
||||
messages.push(Message {
|
||||
name: None,
|
||||
message: title.to_string(),
|
||||
});
|
||||
} else if let Some(title) = savetitle["text"].as_str() {
|
||||
messages.push(Message {
|
||||
name: None,
|
||||
message: title.to_string(),
|
||||
});
|
||||
}
|
||||
} else if let Some(title) = savetitle["text"].as_str() {
|
||||
messages.push(Message {
|
||||
name: None,
|
||||
message: title.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
if !block[Key("text")].is_null() {
|
||||
let tex = &text[NumKey(text_index)];
|
||||
text_index += 1;
|
||||
if tex.is_array() {
|
||||
let lan = match lang {
|
||||
Some(l) => l,
|
||||
None => {
|
||||
for l in tex.kv_keys() {
|
||||
if l.is_str() && l != "vo" && l != "name" {
|
||||
lang = l.as_str();
|
||||
break;
|
||||
}
|
||||
}
|
||||
match lang {
|
||||
Some(l) => l,
|
||||
// No text found, continue to next block
|
||||
None => continue,
|
||||
}
|
||||
}
|
||||
};
|
||||
let mut te = &tex[lan];
|
||||
if te.is_null() {
|
||||
for l in tex.kv_keys() {
|
||||
if l != "vo" && l != "name" {
|
||||
te = &tex[l];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
let name = &tex["name"];
|
||||
let nam = if name.is_array() {
|
||||
if let Some(lang) = lang {
|
||||
if let Some(n) = name[lang].as_string() {
|
||||
Some(n)
|
||||
} else if let Some(n) = name["name"].as_string() {
|
||||
Some(n)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else if let Some(n) = name["name"].as_string() {
|
||||
Some(n)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
for item in te.members() {
|
||||
let message = text::TextGenerator::new().generate(item)?;
|
||||
messages.push(Message {
|
||||
name: nam.clone(),
|
||||
message: message.replace("<rt2>", "\n").replace("<ret2>", "\n"),
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if !block[Key("select")].is_null() {
|
||||
let tex = &text[NumKey(text_index)]["select"];
|
||||
text_index += 1;
|
||||
if tex.is_array() {
|
||||
let lan = match lang {
|
||||
Some(l) => l,
|
||||
None => {
|
||||
for l in tex.kv_keys() {
|
||||
if l.is_str() && l != "vo" && l != "name" {
|
||||
lang = l.as_str();
|
||||
break;
|
||||
}
|
||||
}
|
||||
match lang {
|
||||
Some(l) => l,
|
||||
// No text found, continue to next block
|
||||
None => continue,
|
||||
}
|
||||
}
|
||||
};
|
||||
let mut te = &tex[lan];
|
||||
if te.is_null() {
|
||||
for l in tex.kv_keys() {
|
||||
if l != "vo" && l != "name" {
|
||||
te = &tex[l];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for item in te.members() {
|
||||
if let Some(select) = item.as_str() {
|
||||
messages.push(Message {
|
||||
name: None,
|
||||
message: select.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Ok(messages);
|
||||
}
|
||||
let mut block_name = ast["label"]["top"]["block"]
|
||||
.as_str()
|
||||
.ok_or(anyhow::anyhow!("Missing top block name"))?;
|
||||
let mut block = &ast[block_name];
|
||||
let mut lang: Option<&str> = self.lang.as_ref().map(|s| s.as_str());
|
||||
loop {
|
||||
let savetitle = &block[Key("savetitle")];
|
||||
if savetitle.is_array() {
|
||||
@@ -122,8 +247,8 @@ impl Script for AstScript {
|
||||
Some(l) => l,
|
||||
None => {
|
||||
for l in text.kv_keys() {
|
||||
if l != "vo" {
|
||||
lang = Some(l);
|
||||
if l.is_str() && l != "vo" {
|
||||
lang = l.as_str();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -169,8 +294,8 @@ impl Script for AstScript {
|
||||
Some(l) => l,
|
||||
None => {
|
||||
for l in select.kv_keys() {
|
||||
if l != "vo" {
|
||||
lang = Some(l);
|
||||
if l.is_str() && l != "vo" {
|
||||
lang = l.as_str();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -224,16 +349,169 @@ impl Script for AstScript {
|
||||
) -> Result<()> {
|
||||
let mut ast = self.ast.clone();
|
||||
let root = &mut ast.ast;
|
||||
let mut lang = self.lang.as_ref().map(|s| s.to_string());
|
||||
let mut mess = messages.iter();
|
||||
let mut mes = mess.next();
|
||||
if root["label"]["top"]["block"].is_null() && root["text"].is_array() {
|
||||
let mut text_index = 1i64;
|
||||
let len = root.len();
|
||||
for i in 0..len {
|
||||
if root[i].is_array() {
|
||||
if root[i][Key("savetitle")].is_array() {
|
||||
let lan = self.lang.as_ref().map(|s| s.as_str()).unwrap_or("text");
|
||||
let m = match mes {
|
||||
Some(m) => m,
|
||||
None => return Err(anyhow::anyhow!("Not enough messages.")),
|
||||
};
|
||||
let mut title = m.message.clone();
|
||||
if let Some(repl) = replacement {
|
||||
for (k, v) in &repl.map {
|
||||
title = title.replace(k, v);
|
||||
}
|
||||
}
|
||||
root[i][Key("savetitle")][lan].set_string(title);
|
||||
mes = mess.next();
|
||||
}
|
||||
}
|
||||
if !root[i][Key("text")].is_null() {
|
||||
let lan = match &lang {
|
||||
Some(l) => l.as_str(),
|
||||
None => {
|
||||
for l in root["text"][NumKey(text_index)].kv_keys() {
|
||||
if l.is_str() && l != "vo" && l != "name" {
|
||||
lang = l.as_string();
|
||||
break;
|
||||
}
|
||||
}
|
||||
match lang {
|
||||
Some(ref l) => l.as_str(),
|
||||
// No text found, continue to next block
|
||||
None => continue,
|
||||
}
|
||||
}
|
||||
};
|
||||
if root["text"][NumKey(text_index)]["name"].is_array() {
|
||||
let name = match mes {
|
||||
Some(m) => m.name.clone(),
|
||||
None => return Err(anyhow::anyhow!("Message name is missing.")),
|
||||
};
|
||||
let mut name = match name {
|
||||
Some(n) => n,
|
||||
None => return Err(anyhow::anyhow!("Message name is missing.")),
|
||||
};
|
||||
if let Some(repl) = replacement {
|
||||
for (k, v) in &repl.map {
|
||||
name = name.replace(k, v);
|
||||
}
|
||||
}
|
||||
let nlan = self.lang.as_ref().map(|s| s.as_str()).unwrap_or("name");
|
||||
root["text"][NumKey(text_index)]["name"][nlan].set_string(name);
|
||||
}
|
||||
let origin_count = {
|
||||
let text = &root["text"][NumKey(text_index)];
|
||||
let mut tex = &text[lan];
|
||||
if tex.is_null() {
|
||||
for l in text.kv_keys() {
|
||||
if l != "vo" && l != "name" {
|
||||
tex = &text[l];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
tex.len()
|
||||
};
|
||||
let mut arr = Value::new_array();
|
||||
for _ in 0..origin_count {
|
||||
let m = match mes {
|
||||
Some(m) => m,
|
||||
None => return Err(anyhow::anyhow!("Not enough messages.")),
|
||||
};
|
||||
let mut text = m.message.clone();
|
||||
if let Some(repl) = replacement {
|
||||
for (k, v) in &repl.map {
|
||||
text = text.replace(k, v);
|
||||
}
|
||||
}
|
||||
let v = text::TextParser::new(&text.replace("\n", "<rt2>")).parse()?;
|
||||
arr.push_member(v);
|
||||
mes = mess.next();
|
||||
}
|
||||
root["text"][NumKey(text_index)][lan] = arr;
|
||||
text_index += 1;
|
||||
} else if !root[i][Key("select")].is_null() {
|
||||
let lan = match &lang {
|
||||
Some(l) => l.as_str(),
|
||||
None => {
|
||||
for l in root["text"][NumKey(text_index)]["select"].kv_keys() {
|
||||
if l.is_str() && l != "vo" && l != "name" {
|
||||
lang = l.as_string();
|
||||
break;
|
||||
}
|
||||
}
|
||||
match lang {
|
||||
Some(ref l) => l.as_str(),
|
||||
// No text found, continue to next block
|
||||
None => continue,
|
||||
}
|
||||
}
|
||||
};
|
||||
let count = {
|
||||
let text = &root["text"][NumKey(text_index)]["select"];
|
||||
let mut tex = &text[lan];
|
||||
if tex.is_null() {
|
||||
for l in text.kv_keys() {
|
||||
if l != "vo" && l != "name" {
|
||||
tex = &text[l];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
tex.len()
|
||||
};
|
||||
let mut new_select = Value::new_array();
|
||||
for _ in 0..count {
|
||||
let m = match mes {
|
||||
Some(m) => m,
|
||||
None => return Err(anyhow::anyhow!("Not enough messages.")),
|
||||
};
|
||||
let mut select_text = m.message.clone();
|
||||
if let Some(repl) = replacement {
|
||||
for (k, v) in &repl.map {
|
||||
select_text = select_text.replace(k, v);
|
||||
}
|
||||
}
|
||||
new_select.push_member(Value::Str(select_text));
|
||||
mes = mess.next();
|
||||
}
|
||||
root["text"][NumKey(text_index)]["select"][lan] = new_select;
|
||||
text_index += 1;
|
||||
}
|
||||
}
|
||||
if mes.is_some() || mess.next().is_some() {
|
||||
return Err(anyhow::anyhow!("Not all messages were used."));
|
||||
}
|
||||
let mut writer = Vec::new();
|
||||
let mut dumper = dump::Dumper::new(&mut writer);
|
||||
if self.no_indent {
|
||||
dumper.set_no_indent();
|
||||
} else if let Some(indent) = self.indent {
|
||||
dumper.set_indent(indent);
|
||||
}
|
||||
dumper.set_max_line_width(self.max_line_width);
|
||||
dumper.dump(&ast)?;
|
||||
let data = String::from_utf8(writer)?;
|
||||
let encoded = encode_string(encoding, &data, false)?;
|
||||
file.write_all(&encoded)?;
|
||||
file.flush()?;
|
||||
return Ok(());
|
||||
}
|
||||
let mut block_name = root["label"]["top"]["block"]
|
||||
.as_string()
|
||||
.ok_or(anyhow::anyhow!("Missing top block name"))?;
|
||||
let mut block = &mut root[block_name];
|
||||
let mut mess = messages.iter();
|
||||
let mut mes = mess.next();
|
||||
let mut lang = self.lang.as_ref().map(|s| s.to_string());
|
||||
loop {
|
||||
if block[Key("savetitle")].is_array() {
|
||||
let lan = lang.as_ref().map(|s| s.as_str()).unwrap_or("text");
|
||||
let lan = self.lang.as_ref().map(|s| s.as_str()).unwrap_or("text");
|
||||
let m = match mes {
|
||||
Some(m) => m,
|
||||
None => return Err(anyhow::anyhow!("Not enough messages.")),
|
||||
@@ -252,8 +530,8 @@ impl Script for AstScript {
|
||||
Some(l) => l.as_str(),
|
||||
None => {
|
||||
for l in block["text"].kv_keys() {
|
||||
if l != "vo" {
|
||||
lang = Some(l.to_string());
|
||||
if l.is_str() && l != "vo" {
|
||||
lang = l.as_string();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -328,8 +606,8 @@ impl Script for AstScript {
|
||||
Some(l) => l.as_str(),
|
||||
None => {
|
||||
for l in block["select"].kv_keys() {
|
||||
if l != "vo" {
|
||||
lang = Some(l.to_string());
|
||||
if l.is_str() && l != "vo" {
|
||||
lang = l.as_string();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,17 +28,31 @@ impl<'a> Parser<'a> {
|
||||
|
||||
pub fn try_parse_header(mut self) -> Result<()> {
|
||||
self.erase_whitespace();
|
||||
self.parse_indent(b"astver")?;
|
||||
self.parse_equal()?;
|
||||
self.parse_f64()?;
|
||||
if self.is_indent(b"astver") {
|
||||
self.parse_indent(b"astver")?;
|
||||
self.parse_equal()?;
|
||||
self.parse_f64()?;
|
||||
} else if self.is_indent(b"astname") {
|
||||
self.parse_indent(b"astname")?;
|
||||
self.parse_equal()?;
|
||||
} else if self.is_indent(b"ast") {
|
||||
self.parse_indent(b"ast")?;
|
||||
self.parse_equal()?;
|
||||
} else {
|
||||
return self.error("expected 'astver', 'astname' or 'ast'");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn parse(mut self) -> Result<AstFile> {
|
||||
self.erase_whitespace();
|
||||
self.parse_indent(b"astver")?;
|
||||
self.parse_equal()?;
|
||||
let astver = self.parse_f64()?;
|
||||
let astver = if self.is_indent(b"astver") {
|
||||
self.parse_indent(b"astver")?;
|
||||
self.parse_equal()?;
|
||||
Some(self.parse_f64()?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
self.erase_whitespace();
|
||||
let mut astname = None;
|
||||
if self.is_indent(b"astname") {
|
||||
@@ -262,17 +276,26 @@ impl<'a> Parser<'a> {
|
||||
let key = self.get_indent()?;
|
||||
self.parse_equal()?;
|
||||
let val = self.parse_value()?;
|
||||
Ok(Value::KeyVal((key.to_string(), Box::new(val))))
|
||||
Ok(Value::KeyVal((Box::new(key), Box::new(val))))
|
||||
}
|
||||
|
||||
fn get_indent(&mut self) -> Result<String> {
|
||||
fn get_indent(&mut self) -> Result<Value> {
|
||||
self.erase_whitespace();
|
||||
let start = self.pos;
|
||||
let mut is_first = true;
|
||||
let end = loop {
|
||||
match self.peek() {
|
||||
Some(t) => match t {
|
||||
b'_' | b'a'..=b'z' | b'A'..=b'Z' | b'[' | b']' | b'"' => self.eat_char(),
|
||||
b'_' | b'a'..=b'z' | b'A'..=b'Z' | b'"' => self.eat_char(),
|
||||
b'[' => {
|
||||
self.eat_char();
|
||||
let v = self.parse_value()?;
|
||||
let n = self.next().ok_or(self.error2("unexpected eof"))?;
|
||||
if n != b']' {
|
||||
return self.error("expected ']' after key");
|
||||
}
|
||||
return Ok(v);
|
||||
}
|
||||
b'0'..=b'9' => {
|
||||
if is_first {
|
||||
return self.error("unexpected digit");
|
||||
@@ -290,7 +313,9 @@ impl<'a> Parser<'a> {
|
||||
if data.starts_with(b"[\"") && data.ends_with(b"\"]") {
|
||||
data = &data[2..data.len() - 2];
|
||||
}
|
||||
decode_to_string(self.encoding, data, true).map_err(|e| self.error2(e))
|
||||
Ok(Value::Str(
|
||||
decode_to_string(self.encoding, data, true).map_err(|e| self.error2(e))?,
|
||||
))
|
||||
}
|
||||
|
||||
fn is_indent(&self, indent: &[u8]) -> bool {
|
||||
|
||||
@@ -81,6 +81,10 @@ impl TextGenerator {
|
||||
self.data.push_str(&i.to_string());
|
||||
}
|
||||
Value::KeyVal((k, v)) => {
|
||||
let k = k.as_str().ok_or(anyhow::anyhow!(
|
||||
"Expected key to be a string, but found: {:?}",
|
||||
k
|
||||
))?;
|
||||
self.data.push_str(k);
|
||||
self.data.push('=');
|
||||
match v.as_ref() {
|
||||
@@ -201,7 +205,7 @@ impl<'a> TextParser<'a> {
|
||||
| "9" => self.parse_any_number()?,
|
||||
_ => return self.error("Expected value after key"),
|
||||
};
|
||||
Value::KeyVal((key, Box::new(v)))
|
||||
Value::new_kv(key, v)
|
||||
} else {
|
||||
Value::Str(key)
|
||||
};
|
||||
@@ -368,12 +372,9 @@ fn test_gen() {
|
||||
Value::Str("title".to_string()),
|
||||
Value::Int(1),
|
||||
Value::Float(2.0),
|
||||
Value::KeyVal((
|
||||
"name".to_string(),
|
||||
Box::new(Value::Str("World".to_string())),
|
||||
)),
|
||||
Value::KeyVal(("int".to_string(), Box::new(Value::Int(42)))),
|
||||
Value::KeyVal(("float".to_string(), Box::new(Value::Float(3.0)))),
|
||||
Value::new_kv("name", "World"),
|
||||
Value::new_kv("int", 42),
|
||||
Value::new_kv("float", 3.0),
|
||||
]),
|
||||
Value::Str(">World".to_string()),
|
||||
]);
|
||||
@@ -392,12 +393,9 @@ fn test_parse() {
|
||||
Value::Str("title".to_string()),
|
||||
Value::Int(1),
|
||||
Value::Float(2.0),
|
||||
Value::KeyVal((
|
||||
"name".to_string(),
|
||||
Box::new(Value::Str("World".to_string())),
|
||||
)),
|
||||
Value::KeyVal(("int".to_string(), Box::new(Value::Int(42)))),
|
||||
Value::KeyVal(("float".to_string(), Box::new(Value::Float(3.0)))),
|
||||
Value::new_kv("name", "World"),
|
||||
Value::new_kv("int", 42),
|
||||
Value::new_kv("float", 3.0),
|
||||
]),
|
||||
Value::Str(">World".to_string()),
|
||||
]);
|
||||
|
||||
@@ -7,7 +7,7 @@ pub enum Value {
|
||||
Float(f64),
|
||||
Int(i64),
|
||||
Str(String),
|
||||
KeyVal((String, Box<Value>)),
|
||||
KeyVal((Box<Value>, Box<Value>)),
|
||||
Array(Vec<Value>),
|
||||
Null,
|
||||
}
|
||||
@@ -18,10 +18,33 @@ impl From<String> for Value {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for Value {
|
||||
fn from(s: &'a str) -> Self {
|
||||
Value::Str(s.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i64> for Value {
|
||||
fn from(i: i64) -> Self {
|
||||
Value::Int(i)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for Value {
|
||||
fn from(f: f64) -> Self {
|
||||
Value::Float(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Reprsents a key in nested arrays.
|
||||
/// For example, in the array `{"save", text="test"}`, the key is `"save"`.
|
||||
pub struct Key<'a>(pub &'a str);
|
||||
|
||||
/// Represents a key in key value pairs.
|
||||
/// For example, in the key value pair `[1] = "test"`, the key is `1`.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct NumKey<T: Clone + Copy>(pub T);
|
||||
|
||||
impl<'a> Deref for Key<'a> {
|
||||
type Target = str;
|
||||
|
||||
@@ -96,6 +119,10 @@ impl Value {
|
||||
matches!(self, Value::Array(_))
|
||||
}
|
||||
|
||||
pub fn is_str(&self) -> bool {
|
||||
matches!(self, Value::Str(_))
|
||||
}
|
||||
|
||||
pub fn is_kv(&self) -> bool {
|
||||
matches!(self, Value::KeyVal(_))
|
||||
}
|
||||
@@ -104,17 +131,17 @@ impl Value {
|
||||
matches!(self, Value::Null)
|
||||
}
|
||||
|
||||
pub fn kv_key(&self) -> Option<&str> {
|
||||
pub fn kv_key(&self) -> Option<&Value> {
|
||||
if let Value::KeyVal((k, _)) = self {
|
||||
Some(k)
|
||||
Some(&k)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn kv_keys<'a>(&'a self) -> Box<dyn Iterator<Item = &'a str> + 'a> {
|
||||
pub fn kv_keys<'a>(&'a self) -> Box<dyn Iterator<Item = &'a Value> + 'a> {
|
||||
match self {
|
||||
Value::KeyVal((k, _)) => Box::new(std::iter::once(k.as_str())),
|
||||
Value::KeyVal((k, _)) => Box::new(std::iter::once(&**k)),
|
||||
Value::Array(arr) => Box::new(arr.iter().filter_map(|v| v.kv_key())),
|
||||
_ => Box::new(std::iter::empty()),
|
||||
}
|
||||
@@ -184,8 +211,8 @@ impl Value {
|
||||
Value::Array(Vec::new())
|
||||
}
|
||||
|
||||
pub fn new_kv<S: Into<String>>(key: S, value: Value) -> Self {
|
||||
Value::KeyVal((key.into(), Box::new(value)))
|
||||
pub fn new_kv<K: Into<Value>, V: Into<Value>>(key: K, value: V) -> Self {
|
||||
Value::KeyVal((Box::new(key.into()), Box::new(value.into())))
|
||||
}
|
||||
|
||||
pub fn push_member(&mut self, value: Value) {
|
||||
@@ -274,7 +301,7 @@ impl<'a> IndexMut<&'a str> for Value {
|
||||
unreachable!()
|
||||
}
|
||||
} else {
|
||||
*self = Value::KeyVal((index.to_string(), Box::new(NULL)));
|
||||
*self = Value::KeyVal((Box::new(index.to_string().into()), Box::new(NULL)));
|
||||
if let Value::KeyVal((_, v)) = self {
|
||||
v
|
||||
} else {
|
||||
@@ -295,7 +322,10 @@ impl<'a> IndexMut<&'a str> for Value {
|
||||
}
|
||||
}
|
||||
if let Value::Array(arr) = self {
|
||||
arr.push(Value::KeyVal((index.to_string(), Box::new(NULL))));
|
||||
arr.push(Value::KeyVal((
|
||||
Box::new(index.to_string().into()),
|
||||
Box::new(NULL),
|
||||
)));
|
||||
if let Value::KeyVal((_, v)) = arr.last_mut().unwrap() {
|
||||
v
|
||||
} else {
|
||||
@@ -306,7 +336,10 @@ impl<'a> IndexMut<&'a str> for Value {
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
*self = Value::Array(vec![Value::KeyVal((index.to_string(), Box::new(NULL)))]);
|
||||
*self = Value::Array(vec![Value::KeyVal((
|
||||
Box::new(index.to_string().into()),
|
||||
Box::new(NULL),
|
||||
))]);
|
||||
self.index_mut(index)
|
||||
}
|
||||
}
|
||||
@@ -345,6 +378,237 @@ impl IndexMut<String> for Value {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Index<&'a Value> for Value {
|
||||
type Output = Value;
|
||||
|
||||
fn index(&self, key: &'a Value) -> &Self::Output {
|
||||
match self {
|
||||
Value::KeyVal((k, v)) if k == key => v,
|
||||
Value::Array(arr) => {
|
||||
for item in arr.iter().rev() {
|
||||
if let Value::KeyVal((k, v)) = item {
|
||||
if k == key {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
}
|
||||
&NULL
|
||||
}
|
||||
_ => &NULL,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IndexMut<&'a Value> for Value {
|
||||
fn index_mut(&mut self, index: &'a Value) -> &mut Self::Output {
|
||||
match &self {
|
||||
Value::KeyVal((k, _)) => {
|
||||
if k == index {
|
||||
if let Value::KeyVal((_, v)) = self {
|
||||
v
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
} else {
|
||||
*self = Value::KeyVal((Box::new(index.clone()), Box::new(NULL)));
|
||||
if let Value::KeyVal((_, v)) = self {
|
||||
v
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
Value::Array(arr) => {
|
||||
for (i, item) in arr.iter().enumerate().rev() {
|
||||
if let Value::KeyVal((k, _)) = item {
|
||||
if k == index {
|
||||
if let Value::KeyVal((_, v)) = &mut self[i] {
|
||||
return v;
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Value::Array(arr) = self {
|
||||
arr.push(Value::KeyVal((Box::new(index.clone()), Box::new(NULL))));
|
||||
if let Value::KeyVal((_, v)) = arr.last_mut().unwrap() {
|
||||
v
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
*self = Value::Array(vec![Value::KeyVal((
|
||||
Box::new(index.clone()),
|
||||
Box::new(NULL),
|
||||
))]);
|
||||
self.index_mut(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Index<&'a Box<Value>> for Value {
|
||||
type Output = Value;
|
||||
|
||||
#[inline(always)]
|
||||
fn index(&self, key: &'a Box<Value>) -> &Self::Output {
|
||||
self.index(&**key)
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<NumKey<i64>> for Value {
|
||||
type Output = Value;
|
||||
|
||||
fn index(&self, key: NumKey<i64>) -> &Self::Output {
|
||||
match self {
|
||||
Value::KeyVal((k, v)) if k == key.0 => v,
|
||||
Value::Array(arr) => {
|
||||
for item in arr.iter().rev() {
|
||||
if let Value::KeyVal((k, v)) = item {
|
||||
if k == key.0 {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
}
|
||||
&NULL
|
||||
}
|
||||
_ => &NULL,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<NumKey<i64>> for Value {
|
||||
fn index_mut(&mut self, key: NumKey<i64>) -> &mut Self::Output {
|
||||
match &self {
|
||||
Value::KeyVal((k, _)) => {
|
||||
if k == key.0 {
|
||||
if let Value::KeyVal((_, v)) = self {
|
||||
v
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
} else {
|
||||
*self = Value::KeyVal((Box::new(key.0.into()), Box::new(NULL)));
|
||||
if let Value::KeyVal((_, v)) = self {
|
||||
v
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
Value::Array(arr) => {
|
||||
for (i, item) in arr.iter().enumerate().rev() {
|
||||
if let Value::KeyVal((k, _)) = item {
|
||||
if k == key.0 {
|
||||
if let Value::KeyVal((_, v)) = &mut self[i] {
|
||||
return v;
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Value::Array(arr) = self {
|
||||
arr.push(Value::KeyVal((Box::new(key.0.into()), Box::new(NULL))));
|
||||
if let Value::KeyVal((_, v)) = arr.last_mut().unwrap() {
|
||||
v
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
*self = Value::Array(vec![Value::KeyVal((
|
||||
Box::new(key.0.into()),
|
||||
Box::new(NULL),
|
||||
))]);
|
||||
self.index_mut(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<NumKey<f64>> for Value {
|
||||
type Output = Value;
|
||||
|
||||
fn index(&self, key: NumKey<f64>) -> &Self::Output {
|
||||
match self {
|
||||
Value::KeyVal((k, v)) if k == key.0 => v,
|
||||
Value::Array(arr) => {
|
||||
for item in arr.iter().rev() {
|
||||
if let Value::KeyVal((k, v)) = item {
|
||||
if k == key.0 {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
}
|
||||
&NULL
|
||||
}
|
||||
_ => &NULL,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<NumKey<f64>> for Value {
|
||||
fn index_mut(&mut self, key: NumKey<f64>) -> &mut Self::Output {
|
||||
match &self {
|
||||
Value::KeyVal((k, _)) => {
|
||||
if k == key.0 {
|
||||
if let Value::KeyVal((_, v)) = self {
|
||||
v
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
} else {
|
||||
*self = Value::KeyVal((Box::new(key.0.into()), Box::new(NULL)));
|
||||
if let Value::KeyVal((_, v)) = self {
|
||||
v
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
Value::Array(arr) => {
|
||||
for (i, item) in arr.iter().enumerate().rev() {
|
||||
if let Value::KeyVal((k, _)) = item {
|
||||
if k == key.0 {
|
||||
if let Value::KeyVal((_, v)) = &mut self[i] {
|
||||
return v;
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Value::Array(arr) = self {
|
||||
arr.push(Value::KeyVal((Box::new(key.0.into()), Box::new(NULL))));
|
||||
if let Value::KeyVal((_, v)) = arr.last_mut().unwrap() {
|
||||
v
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
*self = Value::Array(vec![Value::KeyVal((
|
||||
Box::new(key.0.into()),
|
||||
Box::new(NULL),
|
||||
))]);
|
||||
self.index_mut(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Index<&'b Key<'a>> for Value {
|
||||
type Output = Value;
|
||||
|
||||
@@ -410,6 +674,55 @@ impl PartialEq<f64> for Value {
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<str> for Box<Value> {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
**self == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<String> for Box<Value> {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &String) -> bool {
|
||||
**self == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<i64> for Box<Value> {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &i64) -> bool {
|
||||
**self == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<f64> for Box<Value> {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &f64) -> bool {
|
||||
**self == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Value> for Box<Value> {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &Value) -> bool {
|
||||
**self == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialEq<i64> for &'a Box<Value> {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &i64) -> bool {
|
||||
**self == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialEq<f64> for &'a Box<Value> {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &f64) -> bool {
|
||||
**self == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<i64> for Value {
|
||||
fn partial_cmp(&self, other: &i64) -> Option<std::cmp::Ordering> {
|
||||
match self {
|
||||
@@ -428,6 +741,20 @@ impl PartialOrd<f64> for Value {
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<i64> for Box<Value> {
|
||||
#[inline(always)]
|
||||
fn partial_cmp(&self, other: &i64) -> Option<std::cmp::Ordering> {
|
||||
(**self).partial_cmp(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<f64> for Box<Value> {
|
||||
#[inline(always)]
|
||||
fn partial_cmp(&self, other: &f64) -> Option<std::cmp::Ordering> {
|
||||
(**self).partial_cmp(other)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Iter<'a> {
|
||||
iter: std::slice::Iter<'a, Value>,
|
||||
@@ -486,7 +813,7 @@ impl<'a> DoubleEndedIterator for IterMut<'a> {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AstFile {
|
||||
pub astver: f64,
|
||||
pub astver: Option<f64>,
|
||||
pub astname: Option<String>,
|
||||
pub ast: Value,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user