use crate::cst::{Item, ListKind, Node};
pub fn sym(s: &str) -> Node {
Node::Atom(s.to_string())
}
pub fn atom(s: &str) -> Node {
Node::Atom(s.to_string())
}
pub fn string_lit(s: &str) -> Node {
Node::Str(escape_string(s))
}
pub fn quoted_sym(s: &str) -> Node {
Node::Prefixed {
prefix: "'".to_string(),
inner: Box::new(sym(s)),
}
}
pub fn list(children: Vec<Node>) -> Node {
let mut items = Vec::with_capacity(children.len() * 2);
for (i, child) in children.into_iter().enumerate() {
if i > 0 {
items.push(Item::Ws(" ".to_string()));
}
items.push(Item::Node(child));
}
Node::List {
kind: ListKind::Paren,
items,
}
}
pub fn escape_string(s: &str) -> String {
let mut out = String::with_capacity(s.len() + 2);
out.push('"');
for c in s.chars() {
if c == '"' || c == '\\' {
out.push('\\');
}
out.push(c);
}
out.push('"');
out
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn string_lit_escaping_matches_libguix() {
assert_eq!(escape_string("hello"), "\"hello\"");
assert_eq!(escape_string("a\"b"), "\"a\\\"b\"");
assert_eq!(escape_string("a\\b"), "\"a\\\\b\"");
assert_eq!(string_lit("a\"b").to_source(), "\"a\\\"b\"");
}
#[test]
fn built_list_prints_flat() {
let n = list(vec![sym("name"), quoted_sym("guix")]);
assert_eq!(n.to_source(), "(name 'guix)");
}
}