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