Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use super::*;
/// A pass to handle literals and other default values.
pub fn pass(namespace: &mut Namespace) -> Result<()> {
// literals first, because the Default pass might use the value.
namespace.try_visit_mut(|lit: &mut LiteralNode| {
lit.py_lit = render_literal(&lit.lit)?;
Ok(())
})?;
namespace.try_visit_mut(|default: &mut DefaultValueNode| {
default.py_default = render_default(&default.default)?;
// Many types can use the appropriate literal directly.
default.arg_literal = match &default.default {
DefaultValue::Default(tn) => match &tn.ty {
Type::UInt8
| Type::UInt16
| Type::UInt32
| Type::UInt64
| Type::Int8
| Type::Int16
| Type::Int32
| Type::Int64
| Type::Float32
| Type::Float64
| Type::Boolean
| Type::Bytes
| Type::String
| Type::Optional { .. } => default.py_default.clone(),
_ => "_DEFAULT".to_string(),
},
DefaultValue::Literal(ln) => {
if can_use_literal(&ln.lit) {
default.py_default.clone()
} else {
"_DEFAULT".to_string()
}
}
};
default.is_arg_literal = default.py_default == default.arg_literal;
Ok(())
})
}
pub fn can_use_literal(literal: &Literal) -> bool {
match literal {
Literal::Boolean(_)
| Literal::String(_)
| Literal::UInt(_, _, _)
| Literal::Int(_, _, _)
| Literal::Float(_, _)
| Literal::Enum(_, _) => true,
Literal::Some { inner } => match &**inner {
DefaultValue::Literal(inner_lit) => can_use_literal(&inner_lit.lit),
_ => false,
},
_ => false,
}
}
pub(super) fn render_default(default: &DefaultValue) -> Result<String> {
Ok(match default {
DefaultValue::Default(tn) => match &tn.ty {
Type::UInt8
| Type::UInt16
| Type::UInt32
| Type::UInt64
| Type::Int8
| Type::Int16
| Type::Int32
| Type::Int64 => "0".to_string(),
Type::Float32 | Type::Float64 => "0.0".to_string(),
Type::Boolean => "False".to_string(),
Type::Bytes => "b\"\"".to_string(),
Type::String => "\"\"".to_string(),
Type::Record { .. }
| Type::Enum { .. }
| Type::Interface { .. }
| Type::CallbackInterface { .. } => format!("{}()", tn.type_name),
Type::Optional { .. } => "None".to_string(),
Type::Map { .. } => "{}".to_string(),
Type::Sequence { .. } => "[]".to_string(),
Type::Custom { builtin, .. } => {
return render_default(&DefaultValue::Default(TypeNode {
ty: *builtin.clone(),
..tn.clone()
}))
.map_err(|_err| anyhow::anyhow!("Default values not supported for {:?}", tn.ty))
}
_ => bail!("Default values not supported for {:?}", tn.ty),
},
// We assume the Literal pass has already run, so `py_lit` already has a value.
DefaultValue::Literal(lit) => lit.py_lit.clone(),
})
}
fn render_literal(lit: &Literal) -> Result<String> {
Ok(match lit {
Literal::Boolean(true) => "True".to_string(),
Literal::Boolean(false) => "False".to_string(),
Literal::String(s) => format!("\"{s}\""),
Literal::Int(i, radix, _) => match radix {
Radix::Octal => format!("int(0o{i:o})"),
Radix::Decimal => format!("{i}"),
Radix::Hexadecimal => format!("{i:#x}"),
},
Literal::UInt(i, radix, _) => match radix {
Radix::Octal => format!("0o{i:o}"),
Radix::Decimal => format!("{i}"),
Radix::Hexadecimal => format!("{i:#x}"),
},
Literal::Float(value, _) => value.clone(),
Literal::EmptySequence => "[]".to_string(),
Literal::EmptyMap => "{}".to_string(),
Literal::None => "None".to_string(),
Literal::Some { inner } => match **inner {
DefaultValue::Literal(ref lit) => render_literal(&lit.lit)?,
DefaultValue::Default(..) => render_default(inner)?,
},
Literal::Enum(variant, ty) => match &ty.ty {
Type::Enum { name, .. } => format!("{name}.{variant}"),
type_kind => {
bail!("Invalid type for enum literal: {type_kind:?}")
}
},
})
}