#![cfg(feature = "transform")]
use sipha::green::GreenNode;
use sipha::green_builder::GreenBuilder;
use sipha::red::SyntaxNode;
use sipha::types::IntoSyntaxKind;
use leekscript_core::parse;
use leekscript_core::syntax::Kind;
pub use sipha::transform::{transform, TransformResult, Transformer};
fn parse_binary_add_rhs(left: &str, right: &str) -> Option<std::sync::Arc<GreenNode>> {
let src = format!("{} = {} + {};", left.trim(), left.trim(), right.trim());
let root = parse(&src).ok().and_then(|o| o)?;
let program = root.child_nodes().next()?;
let return_stmt = program.child_nodes().next()?;
let expr = return_stmt.child_nodes().next()?;
Some(expr.green().clone())
}
pub struct ExpandAssignAdd;
impl Transformer for ExpandAssignAdd {
fn transform_node(&mut self, node: &SyntaxNode) -> TransformResult {
if node.kind_as::<Kind>() != Some(Kind::NodeExpr) {
return None;
}
if !node.non_trivia_tokens().any(|t| t.text() == "+=") {
return None;
}
let mut child_nodes = node.child_nodes();
let postfix_node = child_nodes.next()?;
let expr_node = child_nodes.next()?;
let left_green = postfix_node.green().clone();
let rhs_green =
parse_binary_add_rhs(&postfix_node.collect_text(), &expr_node.collect_text())
.unwrap_or_else(|| left_green.clone());
Some(GreenBuilder::node_standalone(node.kind(), |b| {
b.child_node(left_green)
.token(Kind::TokOp.into_syntax_kind(), "=", false)
.child_node(rhs_green);
}))
}
}
#[cfg(test)]
mod tests {
use super::*;
use leekscript_core::parse;
#[test]
fn transform_expand_assign_add() {
let source = "var x = 0; x += 10;";
let root = parse(source).unwrap().expect("parse");
let mut t = ExpandAssignAdd;
let new_root = transform(&root, &mut t);
let new_text = new_root.collect_text();
assert!(
new_text.contains("x = "),
"expected assignment in output, got: {:?}",
new_text
);
assert!(
!new_text.contains("+="),
"expected no += in output, got: {:?}",
new_text
);
}
#[test]
fn transform_identity_keeps_tree() {
struct Id;
impl Transformer for Id {
fn transform_node(&mut self, _node: &SyntaxNode) -> TransformResult {
None
}
}
let source = "let a = 1 + 2;";
let root = parse(source).unwrap().expect("parse");
let new_root = transform(&root, &mut Id);
assert!(
sipha_diff::trees_equal(&root, &new_root),
"{}",
sipha_diff::format_diff(&root, &new_root)
);
}
}