use std::collections::HashMap;
use crate::ir::ops::ValueExpr;
use super::super::ast::{
CSharpExpression, CSharpIdentity, CSharpLocalName, CSharpParamName, CSharpPropertyName,
};
pub(super) type Renames = HashMap<String, CSharpExpression>;
pub(super) fn render_value(value: &ValueExpr, renames: &Renames) -> CSharpExpression {
match value {
ValueExpr::Instance => CSharpExpression::Identity(CSharpIdentity::This),
ValueExpr::Var(name) => match renames.get(name) {
Some(expr) => expr.clone(),
None => CSharpExpression::Identity(CSharpIdentity::Local(CSharpLocalName::new(
name.clone(),
))),
},
ValueExpr::Named(name) => {
CSharpExpression::Identity(CSharpIdentity::Param(CSharpParamName::from_source(name)))
}
ValueExpr::Field(parent, field) => CSharpExpression::MemberAccess {
receiver: Box::new(render_value(parent, renames)),
name: CSharpPropertyName::from_source(field.as_str()),
},
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ir::ids::FieldName;
fn empty() -> Renames {
Renames::new()
}
#[test]
fn instance_renders_as_this_keyword() {
assert_eq!(
render_value(&ValueExpr::Instance, &empty()).to_string(),
"this"
);
}
#[test]
fn var_with_no_rename_renders_name_verbatim() {
let expr = render_value(&ValueExpr::Var("v".to_string()), &empty());
assert_eq!(expr.to_string(), "v");
}
#[test]
fn var_with_rename_substitutes_bound_expression() {
let mut renames = Renames::new();
renames.insert(
"v".to_string(),
CSharpExpression::Identity(CSharpIdentity::Local(CSharpLocalName::new("sizeOpt0"))),
);
let expr = render_value(&ValueExpr::Var("v".to_string()), &renames);
assert_eq!(expr.to_string(), "sizeOpt0");
}
#[test]
fn named_converts_source_to_camel_case_bare_reference() {
let expr = render_value(&ValueExpr::Named("my_field".to_string()), &empty());
assert_eq!(expr.to_string(), "myField");
}
#[test]
fn field_access_on_instance_renders_as_this_dot_pascal_case() {
let expr = render_value(
&ValueExpr::Field(Box::new(ValueExpr::Instance), FieldName::new("radius")),
&empty(),
);
assert_eq!(expr.to_string(), "this.Radius");
}
#[test]
fn field_access_chains_through_nested_field() {
let expr = render_value(
&ValueExpr::Field(
Box::new(ValueExpr::Field(
Box::new(ValueExpr::Instance),
FieldName::new("origin"),
)),
FieldName::new("x"),
),
&empty(),
);
assert_eq!(expr.to_string(), "this.Origin.X");
}
#[test]
fn field_access_on_var_respects_renames_for_receiver() {
let mut renames = Renames::new();
renames.insert(
"_v".to_string(),
CSharpExpression::Identity(CSharpIdentity::Local(CSharpLocalName::new("_rebound"))),
);
let expr = render_value(
&ValueExpr::Field(
Box::new(ValueExpr::Var("_v".to_string())),
FieldName::new("radius"),
),
&renames,
);
assert_eq!(expr.to_string(), "_rebound.Radius");
}
}