fix(codegen): string escape
This commit is contained in:
@@ -11,10 +11,15 @@ pub(crate) trait CodegenContext {
|
||||
fn get_sym(&self, id: SymId) -> &str;
|
||||
}
|
||||
|
||||
fn escape_quote_string(s: &str) -> String {
|
||||
let mut escaped = String::with_capacity(s.len() + 2);
|
||||
trait EscapeQuote {
|
||||
fn escape_quote(&self) -> String;
|
||||
}
|
||||
|
||||
impl EscapeQuote for str {
|
||||
fn escape_quote(&self) -> String {
|
||||
let mut escaped = String::with_capacity(self.len() + 2);
|
||||
escaped.push('"');
|
||||
for c in s.chars() {
|
||||
for c in self.chars() {
|
||||
match c {
|
||||
'\\' => escaped.push_str("\\\\"),
|
||||
'\"' => escaped.push_str("\\\""),
|
||||
@@ -27,13 +32,14 @@ fn escape_quote_string(s: &str) -> String {
|
||||
escaped.push('"');
|
||||
escaped
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: CodegenContext> Compile<Ctx> for Ir {
|
||||
fn compile(&self, ctx: &Ctx) -> String {
|
||||
match self {
|
||||
Ir::Int(int) => format!("{int}n"), // Generate BigInt literal
|
||||
Ir::Float(float) => float.to_string(),
|
||||
Ir::Str(s) => escape_quote_string(&s.val),
|
||||
Ir::Str(s) => s.val.escape_quote(),
|
||||
Ir::Path(p) => {
|
||||
// Path needs runtime resolution for interpolated paths
|
||||
let path_expr = ctx.get_ir(p.expr).compile(ctx);
|
||||
@@ -62,7 +68,9 @@ impl<Ctx: CodegenContext> Compile<Ctx> for Ir {
|
||||
format!("expr{}", expr_id.0)
|
||||
}
|
||||
Ir::Builtins(_) => "Nix.builtins".to_string(),
|
||||
&Ir::Builtin(Builtin(name)) => format!("Nix.builtins[\"{}\"]", ctx.get_sym(name)),
|
||||
&Ir::Builtin(Builtin(name)) => {
|
||||
format!("Nix.builtins[{}]", ctx.get_sym(name).escape_quote())
|
||||
}
|
||||
Ir::ConcatStrings(x) => x.compile(ctx),
|
||||
Ir::HasAttr(x) => x.compile(ctx),
|
||||
&Ir::Assert(Assert { assertion, expr }) => {
|
||||
@@ -145,7 +153,7 @@ impl Func {
|
||||
let required = if let Some(req) = &self.param.required {
|
||||
let keys: Vec<_> = req
|
||||
.iter()
|
||||
.map(|&sym| format!("\"{}\"", ctx.get_sym(sym)))
|
||||
.map(|&sym| ctx.get_sym(sym).escape_quote())
|
||||
.collect();
|
||||
format!("[{}]", keys.join(","))
|
||||
} else {
|
||||
@@ -156,7 +164,7 @@ impl Func {
|
||||
let allowed = if let Some(allow) = &self.param.allowed {
|
||||
let keys: Vec<_> = allow
|
||||
.iter()
|
||||
.map(|&sym| format!("\"{}\"", ctx.get_sym(sym)))
|
||||
.map(|&sym| ctx.get_sym(sym).escape_quote())
|
||||
.collect();
|
||||
format!("[{}]", keys.join(","))
|
||||
} else {
|
||||
@@ -226,17 +234,17 @@ impl<Ctx: CodegenContext> Compile<Ctx> for Select {
|
||||
let is_last = i == attr_count - 1;
|
||||
result = match attr {
|
||||
Attr::Str(sym) => {
|
||||
let key = ctx.get_sym(*sym);
|
||||
let key = ctx.get_sym(*sym).escape_quote();
|
||||
if let Some(default) = self.default
|
||||
&& is_last
|
||||
{
|
||||
let default_val = ctx.get_ir(default).compile(ctx);
|
||||
format!(
|
||||
"Nix.selectWithDefault({}, \"{}\", {})",
|
||||
"Nix.selectWithDefault({}, {}, {})",
|
||||
result, key, default_val
|
||||
)
|
||||
} else {
|
||||
format!("Nix.select({}, \"{}\")", result, key)
|
||||
format!("Nix.select({}, {})", result, key)
|
||||
}
|
||||
}
|
||||
Attr::Dynamic(expr_id) => {
|
||||
@@ -267,7 +275,7 @@ impl<Ctx: CodegenContext> Compile<Ctx> for AttrSet {
|
||||
for (&sym, &expr) in &self.stcs {
|
||||
let key = ctx.get_sym(sym);
|
||||
let value = ctx.get_ir(expr).compile(ctx);
|
||||
attrs.push(format!("{}: {}", escape_quote_string(key), value));
|
||||
attrs.push(format!("{}: {}", key.escape_quote(), value));
|
||||
}
|
||||
|
||||
for (key_expr, value_expr) in &self.dyns {
|
||||
@@ -310,9 +318,7 @@ impl<Ctx: CodegenContext> Compile<Ctx> for HasAttr {
|
||||
.rhs
|
||||
.iter()
|
||||
.map(|attr| match attr {
|
||||
Attr::Str(sym) => {
|
||||
format!("\"{}\"", ctx.get_sym(*sym))
|
||||
}
|
||||
Attr::Str(sym) => ctx.get_sym(*sym).escape_quote(),
|
||||
Attr::Dynamic(expr_id) => ctx.get_ir(*expr_id).compile(ctx),
|
||||
})
|
||||
.join(",");
|
||||
|
||||
Reference in New Issue
Block a user