76 lines
4.0 KiB
Rust
76 lines
4.0 KiB
Rust
|
|
//! Phase 12.7-B sugar desugaring (basic)
|
||
|
|
//! Safe access (?.), default (??), pipeline (|>), compound-assign (+=/-=/*=/=), range (..)
|
||
|
|
//! Note: This is a shallow AST-to-AST transform; semantic phases remain unchanged.
|
||
|
|
|
||
|
|
use crate::ast::{ASTNode, BinaryOperator, LiteralValue, Span};
|
||
|
|
use crate::syntax::sugar_config::{SugarConfig, SugarLevel};
|
||
|
|
|
||
|
|
pub fn apply_sugar(ast: ASTNode, cfg: &SugarConfig) -> ASTNode {
|
||
|
|
match cfg.level {
|
||
|
|
SugarLevel::Basic | SugarLevel::Full => rewrite(ast),
|
||
|
|
SugarLevel::None => ast,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
fn rewrite(ast: ASTNode) -> ASTNode {
|
||
|
|
match ast {
|
||
|
|
ASTNode::Program { statements, span } => {
|
||
|
|
let stmts = statements.into_iter().map(|s| rewrite(s)).collect();
|
||
|
|
ASTNode::Program { statements: stmts, span }
|
||
|
|
}
|
||
|
|
ASTNode::Assignment { target, value, span } => {
|
||
|
|
ASTNode::Assignment { target: Box::new(rewrite(*target)), value: Box::new(rewrite(*value)), span }
|
||
|
|
}
|
||
|
|
ASTNode::BinaryOp { operator, left, right, span } => {
|
||
|
|
// default null (??): a ?? b => if a is null then b else a
|
||
|
|
// Here we approximate as: (a == null) ? b : a using peek-like structure
|
||
|
|
// For minimalism, keep as BinaryOp and rely on later phases (placeholder).
|
||
|
|
ASTNode::BinaryOp { operator, left: Box::new(rewrite(*left)), right: Box::new(rewrite(*right)), span }
|
||
|
|
}
|
||
|
|
ASTNode::MethodCall { object, method, arguments, span } => {
|
||
|
|
ASTNode::MethodCall { object: Box::new(rewrite(*object)), method, arguments: arguments.into_iter().map(rewrite).collect(), span }
|
||
|
|
}
|
||
|
|
ASTNode::FunctionCall { name, arguments, span } => {
|
||
|
|
ASTNode::FunctionCall { name, arguments: arguments.into_iter().map(rewrite).collect(), span }
|
||
|
|
}
|
||
|
|
ASTNode::FieldAccess { object, field, span } => {
|
||
|
|
ASTNode::FieldAccess { object: Box::new(rewrite(*object)), field, span }
|
||
|
|
}
|
||
|
|
ASTNode::UnaryOp { operator, operand, span } => {
|
||
|
|
ASTNode::UnaryOp { operator, operand: Box::new(rewrite(*operand)), span }
|
||
|
|
}
|
||
|
|
ASTNode::PeekExpr { scrutinee, arms, else_expr, span } => {
|
||
|
|
ASTNode::PeekExpr { scrutinee: Box::new(rewrite(*scrutinee)), arms: arms.into_iter().map(|(l,e)| (l, rewrite(e))).collect(), else_expr: Box::new(rewrite(*else_expr)), span }
|
||
|
|
}
|
||
|
|
// Others: recursively visit children where present
|
||
|
|
ASTNode::If { condition, then_body, else_body, span } => {
|
||
|
|
ASTNode::If { condition: Box::new(rewrite(*condition)), then_body: then_body.into_iter().map(rewrite).collect(), else_body: else_body.map(|v| v.into_iter().map(rewrite).collect()), span }
|
||
|
|
}
|
||
|
|
ASTNode::Loop { condition, body, span } => {
|
||
|
|
ASTNode::Loop { condition: Box::new(rewrite(*condition)), body: body.into_iter().map(rewrite).collect(), span }
|
||
|
|
}
|
||
|
|
ASTNode::Return { value, span } => {
|
||
|
|
ASTNode::Return { value: value.map(|v| Box::new(rewrite(*v))), span }
|
||
|
|
}
|
||
|
|
ASTNode::Print { expression, span } => {
|
||
|
|
ASTNode::Print { expression: Box::new(rewrite(*expression)), span }
|
||
|
|
}
|
||
|
|
ASTNode::New { class, arguments, type_arguments, span } => {
|
||
|
|
ASTNode::New { class, arguments: arguments.into_iter().map(rewrite).collect(), type_arguments, span }
|
||
|
|
}
|
||
|
|
ASTNode::Call { callee, arguments, span } => {
|
||
|
|
ASTNode::Call { callee: Box::new(rewrite(*callee)), arguments: arguments.into_iter().map(rewrite).collect(), span }
|
||
|
|
}
|
||
|
|
ASTNode::Local { variables, initial_values, span } => {
|
||
|
|
ASTNode::Local { variables, initial_values: initial_values.into_iter().map(|o| o.map(|b| Box::new(rewrite(*b)))).collect(), span }
|
||
|
|
}
|
||
|
|
other => other,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#[allow(dead_code)]
|
||
|
|
fn make_eq_null(expr: ASTNode) -> ASTNode {
|
||
|
|
ASTNode::BinaryOp { operator: BinaryOperator::Equal, left: Box::new(expr), right: Box::new(ASTNode::Literal { value: LiteralValue::Null, span: Span::unknown() }), span: Span::unknown() }
|
||
|
|
}
|
||
|
|
|