# HG changeset patch # User alfadur # Date 1589834638 -10800 # Node ID ca5c7c1de9857714aa7a6a93141dda33dd55acdf # Parent 3f388d2e14667fb85bd10792a935bb2860b5875a add haskell literal formatter diff -r 3f388d2e1466 -r ca5c7c1de985 rust/hedgewars-server/src/server/haskell.rs --- a/rust/hedgewars-server/src/server/haskell.rs Mon May 18 22:39:28 2020 +0300 +++ b/rust/hedgewars-server/src/server/haskell.rs Mon May 18 23:43:58 2020 +0300 @@ -7,24 +7,89 @@ sequence::{delimited, pair, preceded, separated_pair}, IResult, }; -use std::collections::HashMap; +use std::{ + collections::HashMap, + fmt::{Display, Error, Formatter}, +}; type HaskellResult<'a, T> = IResult<&'a [u8], T, ()>; #[derive(Debug, PartialEq)] pub enum HaskellValue { - List(Vec), + Number(u8), + String(String), Tuple(Vec), - String(String), - Number(u8), + List(Vec), + AnonStruct { + name: String, + fields: Vec, + }, Struct { name: String, fields: HashMap, }, - AnonStruct { - name: String, - fields: Vec, - }, +} + +fn write_sequence( + f: &mut Formatter<'_>, + brackets: &[u8; 2], + mut items: std::slice::Iter, +) -> Result<(), Error> { + write!(f, "{}", brackets[0] as char)?; + while let Some(value) = items.next() { + write!(f, "{}", value); + if !items.as_slice().is_empty() { + write!(f, ", ")?; + } + } + if brackets[1] != b'\0' { + write!(f, "{}", brackets[1] as char) + } else { + Ok(()) + } +} + +fn write_text(f: &mut Formatter<'_>, text: &str) -> Result<(), Error> { + write!(f, "\"")?; + for c in text.chars() { + if c.is_ascii() && !(c as u8).is_ascii_control() { + write!(f, "{}", c); + } else { + let mut bytes = [0u8; 4]; + let size = c.encode_utf8(&mut bytes).len(); + for byte in &bytes[0..size] { + write!(f, "\\{:03}", byte); + } + } + } + write!(f, "\"") +} + +impl Display for HaskellValue { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { + match self { + HaskellValue::Number(value) => write!(f, "{}", value), + HaskellValue::String(value) => write_text(f, value), + HaskellValue::Tuple(items) => write_sequence(f, b"()", items.iter()), + HaskellValue::List(items) => write_sequence(f, b"[]", items.iter()), + HaskellValue::AnonStruct { name, fields } => { + write!(f, "{} ", name); + write_sequence(f, b" \0", fields.iter()) + } + HaskellValue::Struct { name, fields } => { + write!(f, "{} {{", name); + let fields = fields.iter().collect::>(); + let mut items = fields.iter(); + while let Some((field_name, value)) = items.next() { + write!(f, "{} = {}", field_name, value); + if !items.as_slice().is_empty() { + write!(f, ", ")?; + } + } + write!(f, "}}") + } + } + } } fn comma(input: &[u8]) -> HaskellResult<&[u8]> { @@ -105,7 +170,6 @@ map(tag("GS"), |_| &b"\x1D"[..]), map(tag("RS"), |_| &b"\x1E"[..]), map(tag("US"), |_| &b"\x1F"[..]), - map(tag("SP"), |_| &b"\x20"[..]), map(tag("DEL"), |_| &b"\x7F"[..]), )), ))(input)