Fix lua parse/dump bug

This commit is contained in:
2025-07-23 21:03:21 +08:00
parent 00439d8e6b
commit f738bbf25b
7 changed files with 237 additions and 35 deletions

View File

@@ -1,4 +1,5 @@
use super::types::*;
use crate::utils::escape::*;
use std::io::Write;
struct LenChecker {
@@ -24,9 +25,21 @@ impl LenChecker {
}
}
Value::Int(i) => self.current_len += format!("{}", i).len(),
Value::Str(s) => self.current_len += s.len() + 2,
Value::Str(s) => {
self.current_len += s.len()
+ if lua_str_contains_need_escape(s) {
4
} else {
2
}
}
Value::KeyVal((k, v)) => {
self.current_len += k.as_bytes().len() + 3;
self.current_len += k.as_bytes().len()
+ if lua_key_contains_need_escape(k) {
7
} else {
3
};
if !self.check(v) {
return false;
}
@@ -96,19 +109,35 @@ impl<'a> Dumper<'a> {
self.writer.write(b"astver=")?;
self.dump_f64(&ast.astver)?;
if let Some(astname) = &ast.astname {
self.writer.write(b"\nastname = \"")?;
self.writer.write(astname.as_bytes())?;
self.writer.write(b"\nastname = ")?;
if lua_str_contains_need_escape(astname) {
self.writer.write(b"[[")?;
self.writer.write(astname.as_bytes())?;
self.writer.write(b"]]")?;
} else {
self.writer.write(b"\"")?;
self.writer.write(astname.as_bytes())?;
self.writer.write(b"\"")?;
}
};
self.writer.write(b"\"\nast=")?;
self.writer.write(b"\nast=")?;
self.dump_value(&ast.ast)?;
} else {
self.writer.write(b"astver = ")?;
self.dump_f64(&ast.astver)?;
if let Some(astname) = &ast.astname {
self.writer.write(b"\nastname = \"")?;
self.writer.write(astname.as_bytes())?;
self.writer.write(b"\nastname = ")?;
if lua_str_contains_need_escape(&astname) {
self.writer.write(b"[[")?;
self.writer.write(astname.as_bytes())?;
self.writer.write(b"]]")?;
} else {
self.writer.write(b"\"")?;
self.writer.write(astname.as_bytes())?;
self.writer.write(b"\"")?;
}
};
self.writer.write(b"\"\nast = ")?;
self.writer.write(b"\nast = ")?;
self.current_line_width = 6;
self.dump_value(&ast.ast)?;
}
@@ -122,13 +151,25 @@ impl<'a> Dumper<'a> {
Value::Float(f) => self.dump_f64(f)?,
Value::Int(i) => write!(self.writer, "{}", i)?,
Value::Str(s) => {
self.writer.write(b"\"")?;
self.writer.write(s.as_bytes())?;
self.writer.write(b"\"")?;
if lua_str_contains_need_escape(s) {
self.writer.write(b"[[")?;
self.writer.write(s.as_bytes())?;
self.writer.write(b"]]")?;
} else {
self.writer.write(b"\"")?;
self.writer.write(s.as_bytes())?;
self.writer.write(b"\"")?;
}
}
Value::KeyVal((k, v)) => {
self.writer.write(k.as_bytes())?;
self.writer.write(b"=")?;
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"=")?;
}
self.dump_value(v)?;
}
Value::Array(arr) => {
@@ -150,15 +191,28 @@ impl<'a> Dumper<'a> {
Value::Float(f) => self.dump_f64(f)?,
Value::Int(i) => write!(self.writer, "{}", i)?,
Value::Str(s) => {
self.writer.write(b"\"")?;
self.writer.write(s.as_bytes())?;
self.writer.write(b"\"")?;
if lua_str_contains_need_escape(s) {
self.writer.write(b"[[")?;
self.writer.write(s.as_bytes())?;
self.writer.write(b"]]")?;
} else {
self.writer.write(b"\"")?;
self.writer.write(s.as_bytes())?;
self.writer.write(b"\"")?;
}
}
Value::KeyVal((k, v)) => {
let bytes = k.as_bytes();
self.writer.write(bytes)?;
self.writer.write(b" = ")?;
self.current_line_width += bytes.len() + 3;
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;
}
if v.is_array() {
let tlen = self.current_line_width + self.current_indent;
if tlen < self.max_line_width {
@@ -215,14 +269,25 @@ impl<'a> Dumper<'a> {
Value::Float(f) => self.dump_f64(f)?,
Value::Int(i) => write!(self.writer, "{}", i)?,
Value::Str(s) => {
self.writer.write(b"\"")?;
self.writer.write(s.as_bytes())?;
self.writer.write(b"\"")?;
if lua_str_contains_need_escape(s) {
self.writer.write(b"[[")?;
self.writer.write(s.as_bytes())?;
self.writer.write(b"]]")?;
} else {
self.writer.write(b"\"")?;
self.writer.write(s.as_bytes())?;
self.writer.write(b"\"")?;
}
}
Value::KeyVal((k, v)) => {
let bytes = k.as_bytes();
self.writer.write(bytes)?;
self.writer.write(b"=")?;
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"=")?;
}
self.dump_value_in_one(v)?;
}
Value::Array(arr) => {

View File

@@ -50,6 +50,7 @@ pub struct AstScript {
indent: Option<usize>,
max_line_width: usize,
no_indent: bool,
lang: Option<String>,
}
impl AstScript {
@@ -61,6 +62,7 @@ impl AstScript {
indent: config.artemis_indent,
max_line_width: config.artemis_max_line_width,
no_indent: config.artemis_no_indent,
lang: config.artemis_ast_lang.clone(),
})
}
}
@@ -81,13 +83,28 @@ impl Script for AstScript {
.as_str()
.ok_or(anyhow::anyhow!("Missing top block name"))?;
let mut block = &ast[block_name];
let mut lang = None;
let mut lang: Option<&str> = self.lang.as_ref().map(|s| s.as_str());
loop {
if let Some(save_title) = block[Key("savetitle")]["text"].as_str() {
messages.push(Message {
name: None,
message: save_title.to_string(),
});
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(),
});
}
}
let text = &block["text"];
if text.is_array() {

View File

@@ -1,6 +1,7 @@
use super::types::*;
use crate::types::*;
use crate::utils::encoding::*;
use crate::utils::escape::unescape_lua_str;
use anyhow::Result;
pub struct Parser<'a> {
@@ -61,6 +62,19 @@ impl<'a> Parser<'a> {
match self.peek() {
Some(t) => match t {
b'"' => return self.parse_str().map(|x| Value::Str(x.to_string())),
b'[' => {
self.eat_char();
match self.peek().ok_or(self.error2("unexpected eof"))? {
b'[' => {
self.pos -= 1; // Rewind to the first '['
self.parse_raw_str().map(|x| Value::Str(x))
}
_ => {
self.pos -= 1;
self.parse_key_val()
}
}
}
b'-' | b'.' | b'0'..=b'9' => return self.parse_any_number(),
b'n' => {
if self.is_indent(b"nil") {
@@ -70,7 +84,7 @@ impl<'a> Parser<'a> {
self.parse_key_val()
}
}
b'_' | b'a'..=b'z' | b'A'..=b'Z' | b'[' | b']' => return self.parse_key_val(),
b'_' | b'a'..=b'z' | b'A'..=b'Z' | b']' => return self.parse_key_val(),
b'{' => return self.parse_array(),
_ => return self.error(format!("unexpected token: {}", t)),
},
@@ -146,12 +160,40 @@ impl<'a> Parser<'a> {
self.erase_whitespace();
self.parse_indent(b"\"")?;
let start = self.pos;
let mut pc = None;
let end = loop {
match self.next() {
Some(c) => {
if c == b'"' {
break self.pos - 1;
if pc.is_none_or(|x| x != b'\\') {
break self.pos - 1;
}
}
pc = Some(c);
}
None => return self.error("unexpected eof"),
}
};
Ok(unescape_lua_str(
&decode_to_string(self.encoding, &self.str[start..end], true)
.map_err(|e| self.error2(e))?,
))
}
fn parse_raw_str(&mut self) -> Result<String> {
self.erase_whitespace();
self.parse_indent(b"[[")?;
let start = self.pos;
let mut pc = None;
let end = loop {
match self.next() {
Some(c) => {
if c == b']' {
if pc.is_some_and(|x| x == b']') {
break self.pos - 2;
}
}
pc = Some(c);
}
None => return self.error("unexpected eof"),
}
@@ -213,7 +255,7 @@ impl<'a> Parser<'a> {
let end = loop {
match self.peek() {
Some(t) => match t {
b'_' | b'a'..=b'z' | b'A'..=b'Z' | b'[' | b']' => self.eat_char(),
b'_' | b'a'..=b'z' | b'A'..=b'Z' | b'[' | b']' | b'"' => self.eat_char(),
b'0'..=b'9' => {
if is_first {
return self.error("unexpected digit");
@@ -227,7 +269,11 @@ impl<'a> Parser<'a> {
}
is_first = false;
};
decode_to_string(self.encoding, &self.str[start..end], true).map_err(|e| self.error2(e))
let mut data = &self.str[start..end];
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))
}
fn is_indent(&self, indent: &[u8]) -> bool {