1234use linked_hash_map::LinkedHashMap;5use peg::str::LineCol;6use se_impl::MySerialize;7use serde::{Deserialize, Serialize};89mod de_impl;10mod se_impl;11mod to_string;1213pub use to_string::escape_string;1415#[derive(thiserror::Error, Debug)]16pub enum Error {17 #[error("bad number")]18 BadNumber,19 #[error("expected {0}")]20 Expected(&'static str),21 #[error("parse error")]22 ParseError(#[from] peg::error::ParseError<LineCol>),23 #[error("{0}")]24 Custom(String),25 #[error("io: {0}")]26 Io(#[from] std::io::Error),27 #[error("fmt: {0}")]28 Fmt(#[from] std::fmt::Error),29}3031#[derive(Debug)]32pub enum Value {33 Number(i64),34 String(String),35 Boolean(bool),36 Object(LinkedHashMap<String, Value>),37 Array(Vec<Value>),38 Null,39}4041fn count_spaces(l: &str) -> usize {42 l.chars().take_while(|&c| c == ' ').count()43}44fn is_significant(l: &str) -> bool {45 count_spaces(l) != l.len()46}4748fn dedent(l: &str, by: usize) -> &str {49 assert!(50 l[0..by.min(l.len())].chars().all(|c| c == ' '),51 "dedent calculation is wrong"52 );53 &l[by.min(l.len())..]54}5556fn process_multiline(lines: Vec<&str>) -> String {57 58 59 let dedent_by = lines60 .iter()61 .copied()62 .filter(|c| is_significant(c))63 .map(count_spaces)64 .min()65 .unwrap_or(0);6667 let mut out = String::new();6869 let mut had_first = false;70 for (i, line) in lines.into_iter().enumerate() {71 72 if i == 0 && !is_significant(line) {73 continue;74 }75 if had_first {76 out.push('\n');77 }78 had_first = true;79 80 for (i, part) in dedent(line, dedent_by).split("'''").enumerate() {81 if i != 0 {82 out.push_str(r#"""""#);83 }84 85 out.push_str(&part.replace("''${", "${").replace("''\\t", "\t"));86 }87 }8889 out90}9192peg::parser! {93pub grammar nixlike() for str {94 rule number() -> i6495 = quiet! { v:$(['0'..='9' | '+' | '-']+) {? v.parse().map_err(|_| "<number>")} } / expected!("<number>")96 rule string_char() -> &'input str97 = "\\\"" { "\"" }98 / "\\\\" { "\\" }99 / "\\n" { "\n" }100 / "\\t" { "\t" }101 / "\\r" { "\r" }102 / "\\$" { "$" }103 / c:$([_]) { c }104 rule string() -> String = singleline_string() / multiline_string();105 rule singleline_string() -> String106 = quiet! { "\"" v:(!"\"" c:string_char() {c})* "\"" { v.into_iter().collect() } } / expected!("<string>")107 pub rule multiline_string() -> String108 = "''"109 110 111 lines:$(("'''" / !"''" [_])*) "''"112 {113 process_multiline(lines.split('\n').collect())114 }115 rule boolean() -> bool116 = quiet! { "true" {true}117 / "false" {false} } / expected!("<boolean>")118 rule indent() -> String119 = quiet! {120 s:$(['a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '-']+) { s.to_owned() }121 / "\"" s:$(['a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '-' | '.']+) "\"" { s.to_owned() }122 } / expected!("<identifier>")123 rule object() -> LinkedHashMap<String, Value>124 = "{" _125 e:(k:indent()++(_ "." _) _ "=" _ v:value() _ ";" _ {(k, v)})*126 "}" {?127 let mut out = LinkedHashMap::new();128 for (k, v) in e {129 let mut map = &mut out;130 for v in k.iter().take(k.len() - 1) {131 map = match map.entry(v.clone()).or_insert_with(|| Value::Object(Default::default())) {132 Value::Object(v) => v,133 _ => return Err("expected object"),134 }135 }136137 let key = k.into_iter().last().unwrap();138 if map.contains_key(&key) {139 return Err("can't override object");140 }141 map.insert(key, v);142 }143 Ok(out)144 }145146 rule array() -> Vec<Value>147 = "[" _ v:value()**_ _ "]" {v}148149 rule value() -> Value150 = o:object() { Value::Object(o) }151 / a:array() { Value::Array(a) }152 / s:string() { Value::String(s) }153 / "null" { Value::Null }154 / b:boolean() { Value::Boolean(b) }155 / n:number() { Value::Number(n) }156157 pub rule root() -> Value158 = _ v:value() _ { v }159160 rule _()161 = ( quiet!{ [' ' | '\t' | '\n']+ }162 / "#" (!['\n'] [_])* "\n" )*163}164}165166pub fn parse_str<'de, D: Deserialize<'de>>(s: &str) -> Result<D, Error> {167 let value = nixlike::root(s)?;168 D::deserialize(value)169}170171pub fn parse_value<'de, D: Deserialize<'de>>(value: Value) -> Result<D, Error> {172 D::deserialize(value)173}174175pub fn serialize_value_pretty(value: Value) -> String {176 to_string::write_nix(&value)177}178179pub fn serialize<S: Serialize>(value: S) -> Result<String, Error> {180 let value: Value = value.serialize(MySerialize)?;181 Ok(serialize_value_pretty(value))182}183184pub fn format_identifier(i: &str) -> String {185 let mut out = String::new();186 to_string::write_identifier(i, &mut out);187 out188}189190#[test]191fn test() {192 assert_eq!(serialize("Hello\nworld").unwrap(), "\"Hello\\nworld\"\n");193}194pub fn format_nix(value: &String) -> String {195 let (_, out) = alejandra::format::in_memory("".to_owned(), value.to_owned());196 out197}198199#[test]200fn parse_multiline() {201 assert_eq!(nixlike::multiline_string("''\n''").expect("parse"), "");202 assert_eq!(nixlike::multiline_string("''\n\n''").expect("parse"), "\n");203 assert_eq!(nixlike::multiline_string("''t\n''").expect("parse"), "t\n");204 assert_eq!(nixlike::multiline_string("''''").expect("parse"), "");205 assert_eq!(nixlike::multiline_string("'' ''").expect("parse"), "");206}