175 lines
5.1 KiB
Rust
175 lines
5.1 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(),
|
|
}
|
|
}
|