mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 23:04:49 +00:00
Interpolate strings by desugaring to Str.concat
We could definitely make this more efficent by allocating enough space for the final string and then copying the contents of each of the pieces into it one by one. We don't do that yet though!
This commit is contained in:
parent
2e15443c8c
commit
37a254cef3
5 changed files with 60 additions and 96 deletions
|
@ -45,12 +45,6 @@ impl Output {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum StrSegment {
|
||||
Interpolation(Located<Expr>),
|
||||
Plaintext(InlinableString),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Expr {
|
||||
// Literals
|
||||
|
@ -62,7 +56,7 @@ pub enum Expr {
|
|||
// Int and Float store a variable to generate better error messages
|
||||
Int(Variable, i64),
|
||||
Float(Variable, f64),
|
||||
Str(Vec<StrSegment>),
|
||||
Str(InlinableString),
|
||||
List {
|
||||
list_var: Variable, // required for uniqueness of the list
|
||||
elem_var: Variable,
|
||||
|
@ -1333,10 +1327,7 @@ fn flatten_str_literal<'a>(
|
|||
use ast::StrLiteral::*;
|
||||
|
||||
match literal {
|
||||
PlainLine(str_slice) => (
|
||||
Expr::Str(vec![StrSegment::Plaintext((*str_slice).into())]),
|
||||
Output::default(),
|
||||
),
|
||||
PlainLine(str_slice) => (Expr::Str((*str_slice).into()), Output::default()),
|
||||
Line(segments) => flatten_str_lines(env, var_store, scope, &[segments]),
|
||||
Block(lines) => flatten_str_lines(env, var_store, scope, lines),
|
||||
}
|
||||
|
@ -1350,6 +1341,11 @@ fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
enum StrSegment {
|
||||
Interpolation(Located<Expr>),
|
||||
Plaintext(InlinableString),
|
||||
}
|
||||
|
||||
fn flatten_str_lines<'a>(
|
||||
env: &mut Env<'a>,
|
||||
var_store: &mut VarStore,
|
||||
|
@ -1397,6 +1393,9 @@ fn flatten_str_lines<'a>(
|
|||
},
|
||||
Interpolated(loc_expr) => {
|
||||
if is_valid_interpolation(loc_expr.value) {
|
||||
// Interpolations desugar to Str.concat calls
|
||||
output.references.calls.insert(Symbol::STR_CONCAT);
|
||||
|
||||
if !buf.is_empty() {
|
||||
segments.push(StrSegment::Plaintext(buf.into()));
|
||||
|
||||
|
@ -1432,7 +1431,45 @@ fn flatten_str_lines<'a>(
|
|||
segments.push(StrSegment::Plaintext(buf.into()));
|
||||
}
|
||||
|
||||
(Expr::Str(segments), output)
|
||||
(desugar_str_segments(var_store, segments), output)
|
||||
}
|
||||
|
||||
/// Resolve stirng interpolations by desugaring a sequence of StrSegments
|
||||
/// into nested calls to Str.concat
|
||||
fn desugar_str_segments<'a>(var_store: &mut VarStore, segments: Vec<StrSegment>) -> Expr {
|
||||
use StrSegment::*;
|
||||
|
||||
let mut iter = segments.into_iter().rev();
|
||||
let mut loc_expr = match iter.next() {
|
||||
Some(Plaintext(string)) => Located::new(0, 0, 0, 0, Expr::Str(string.into())),
|
||||
Some(Interpolation(loc_expr)) => loc_expr,
|
||||
None => {
|
||||
// No segments? Empty string!
|
||||
|
||||
Located::new(0, 0, 0, 0, Expr::Str("".into()))
|
||||
}
|
||||
};
|
||||
|
||||
for seg in iter {
|
||||
let loc_new_expr = match seg {
|
||||
Plaintext(string) => Located::new(0, 0, 0, 0, Expr::Str(string.into())),
|
||||
Interpolation(loc_interpolated_expr) => loc_interpolated_expr,
|
||||
};
|
||||
|
||||
let fn_expr = Located::new(0, 0, 0, 0, Expr::Var(Symbol::STR_CONCAT));
|
||||
let expr = Expr::Call(
|
||||
Box::new((var_store.fresh(), fn_expr, var_store.fresh())),
|
||||
vec![
|
||||
(var_store.fresh(), loc_new_expr),
|
||||
(var_store.fresh(), loc_expr),
|
||||
],
|
||||
CalledVia::Space,
|
||||
);
|
||||
|
||||
loc_expr = Located::new(0, 0, 0, 0, expr);
|
||||
}
|
||||
|
||||
loc_expr.value
|
||||
}
|
||||
|
||||
/// Returns the char that would have been originally parsed to
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue