From 5364c9c1bc61d0fa90c7af2e7c9479a3918dbb72 Mon Sep 17 00:00:00 2001 From: Lucien Greathouse Date: Thu, 16 Apr 2020 12:00:02 -0700 Subject: [PATCH] Fix Lua string escaping. Closes #314. --- CHANGELOG.md | 1 + src/lua_ast.rs | 51 ++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34ba10c6..4bd0ed2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased Changes * Fixed crash when malformed CSV files are put into a project. ([#310](https://github.com/rojo-rbx/rojo/issues/310)) +* Fixed incorrect string escaping when producing Lua code from JSON files. ([#314](https://github.com/rojo-rbx/rojo/issues/314)) * Updated default place template to take advantage of [#210](https://github.com/rojo-rbx/rojo/pull/210). ## [6.0.0 Release Candidate 1](https://github.com/rojo-rbx/rojo/releases/tag/v6.0.0-rc.1) (March 29, 2020) diff --git a/src/lua_ast.rs b/src/lua_ast.rs index ace9b4d7..b29370b4 100644 --- a/src/lua_ast.rs +++ b/src/lua_ast.rs @@ -21,6 +21,18 @@ trait FmtLua { } } +struct DisplayLua(T); + +impl fmt::Display for DisplayLua +where + T: FmtLua, +{ + fn fmt(&self, output: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut stream = LuaStream::new(output); + self.0.fmt_lua(&mut stream) + } +} + pub(crate) enum Statement { Return(Expression), } @@ -125,16 +137,37 @@ impl FmtLua for f64 { } } +/// Wrapper struct to display the wrapped string using Lua's string escaping +/// rules. +struct LuaEscape<'a>(&'a str); + +impl fmt::Display for LuaEscape<'_> { + fn fmt(&self, output: &mut fmt::Formatter<'_>) -> fmt::Result { + for c in self.0.chars() { + match c { + '"' => output.write_str("\\\"")?, + '\r' => output.write_str("\\r")?, + '\n' => output.write_str("\\n")?, + '\t' => output.write_str("\\t")?, + '\\' => output.write_str("\\\\")?, + _ => output.write_char(c)?, + } + } + + Ok(()) + } +} + impl FmtLua for String { fn fmt_lua(&self, output: &mut LuaStream<'_>) -> fmt::Result { - write!(output, "\"{}\"", self) + write!(output, "\"{}\"", LuaEscape(self)) } fn fmt_table_key(&self, output: &mut LuaStream<'_>) -> fmt::Result { if is_valid_ident(self) { write!(output, "{}", self) } else { - write!(output, "[\"{}\"]", self) + write!(output, "[\"{}\"]", LuaEscape(self)) } } } @@ -277,3 +310,17 @@ impl<'a> LuaStream<'a> { self.inner.write_str("\n") } } + +#[cfg(test)] +mod test { + use super::*; + + /// Regression test for https://github.com/rojo-rbx/rojo/issues/314 + #[test] + fn bug_314() { + let my_value = "\"\r\n\t\\".to_owned(); + let displayed = format!("{}", DisplayLua(my_value)); + + assert_eq!(displayed, "\"\\\"\\r\\n\\t\\\\\""); + } +}