complete string interpolation

This commit is contained in:
Scott Richmond 2024-12-04 19:07:03 -05:00
parent b6c4c6375b
commit c9038fd8fb
3 changed files with 66 additions and 6 deletions

View File

@ -58,7 +58,12 @@ use crate::base::*;
pub fn main() { pub fn main() {
let src = " let src = "
\"thing\" let foo = :foo
let bar = 42
let baz = \"foo bar baz\"
let quux = (1, 2, [3, 4, #{:five 6, :seven 8}])
\"{foo} {bar} {baz}
{quux} {fuzz} TADA!\"
"; ";
let (tokens, lex_errs) = lexer().parse(src).into_output_errors(); let (tokens, lex_errs) = lexer().parse(src).into_output_errors();
if !lex_errs.is_empty() { if !lex_errs.is_empty() {
@ -73,13 +78,13 @@ pub fn main() {
let (ast, _) = parser() let (ast, _) = parser()
.parse(Stream::from_iter(to_parse).map((0..src.len()).into(), |(t, s)| (t, s))) .parse(Stream::from_iter(to_parse).map((0..src.len()).into(), |(t, s)| (t, s)))
.unwrap(); .unwrap();
println!("{}", ast); // println!("{}", ast);
// let mut ctx = base(); let mut ctx = base();
// let result = eval(&ast, &mut ctx).unwrap(); let result = eval(&ast, &mut ctx).unwrap();
// println!("{}", result); println!("{}", result);
// struct_scalpel::print_dissection_info::<value::Value>() // struct_scalpel::print_dissection_info::<value::Value>()
// struct_scalpel::print_dissection_info::<parser::Ast>(); // struct_scalpel::print_dissection_info::<parser::Ast>();

View File

@ -175,3 +175,37 @@ impl<'src> PartialEq for Value<'src> {
} }
impl Eq for Value<'_> {} impl Eq for Value<'_> {}
impl Value<'_> {
pub fn interpolate(&self) -> String {
match self {
Value::Nil => String::new(),
Value::Boolean(b) => format!("{b}"),
Value::Number(n) => format!("{n}"),
Value::Keyword(k) => format!(":{k}"),
Value::AllocatedString(s) => format!("{s}"),
Value::InternedString(s) => s.to_string(),
Value::Box(_, x) => x.borrow().interpolate(),
Value::Tuple(xs) => xs
.iter()
.map(|x| x.interpolate())
.collect::<Vec<_>>()
.join(", "),
Value::List(xs) => xs
.iter()
.map(|x| x.interpolate())
.collect::<Vec<_>>()
.join(", "),
Value::Dict(xs) => xs
.iter()
.map(|(k, v)| format!(":{} {}", k, v.interpolate()))
.collect::<Vec<_>>()
.join(", "),
Value::Fn(x) => format!("fn {}", x.name.to_string()),
Value::Placeholder => unreachable!(),
Value::Args(_) => unreachable!(),
Value::Recur(_) => unreachable!(),
Value::Base(_) => unreachable!(),
}
}
}

View File

@ -282,7 +282,28 @@ pub fn eval<'src, 'a>(
Ast::Number(n) => Ok(Value::Number(*n)), Ast::Number(n) => Ok(Value::Number(*n)),
Ast::Keyword(k) => Ok(Value::Keyword(k)), Ast::Keyword(k) => Ok(Value::Keyword(k)),
Ast::String(s) => Ok(Value::InternedString(s)), Ast::String(s) => Ok(Value::InternedString(s)),
Ast::Interpolated(s) => todo!(), Ast::Interpolated(parts) => {
let mut interpolated = String::new();
for part in parts {
match &part.0 {
StringPart::Data(s) => interpolated.push_str(s.as_str()),
StringPart::Word(w) => {
let val = if let Some((_, value)) =
ctx.iter().rev().find(|(name, _)| w == name)
{
value.clone()
} else {
return Err(LudusError {
msg: format!("unbound name {w}"),
});
};
interpolated.push_str(val.interpolate().as_str())
}
StringPart::Inline(_) => unreachable!(),
}
}
Ok(Value::AllocatedString(Rc::new(interpolated)))
}
Ast::Block(exprs) => { Ast::Block(exprs) => {
let to = ctx.len(); let to = ctx.len();
let mut result = Value::Nil; let mut result = Value::Nil;