1use sway_core::{
2 AstNode, AstNodeContent, Declaration, Expression, ExpressionKind, IfExpression, ParseTree,
3 ReturnStatement,
4};
5
6use sway_types::span::Span;
7
8use crate::traversal_helper::{
9 format_data_types, format_delineated_path, format_include_statement, format_use_statement,
10};
11
12#[derive(Debug)]
16pub struct Change {
17 pub text: String,
18 pub start: usize,
19 pub end: usize,
20}
21
22impl Change {
23 fn new(span: &Span, change_type: ChangeType) -> Self {
24 let text = match change_type {
25 ChangeType::Struct => format_data_types(span.as_str()),
26 ChangeType::Enum => format_data_types(span.as_str()),
27 ChangeType::IncludeStatement => format_include_statement(span.as_str()),
28 ChangeType::UseStatement => format_use_statement(span.as_str()),
29 ChangeType::DelineatedPath => format_delineated_path(span.as_str()),
30 };
31
32 Self {
33 text,
34 start: span.start(),
35 end: span.end(),
36 }
37 }
38}
39
40#[derive(Debug)]
41enum ChangeType {
42 Struct,
43 Enum,
44 IncludeStatement,
45 UseStatement,
46 DelineatedPath,
47}
48
49pub fn traverse_for_changes(parse_tree: &ParseTree) -> Vec<Change> {
51 let mut changes = vec![];
52
53 for node in &parse_tree.root_nodes {
54 traverse_ast_node(node, &mut changes);
55 }
56
57 changes.sort_by(|a, b| a.start.cmp(&b.start));
58
59 changes
60}
61
62fn traverse_ast_node(ast_node: &AstNode, changes: &mut Vec<Change>) {
63 match &ast_node.content {
64 AstNodeContent::Declaration(dec) => handle_declaration(dec, ast_node, changes),
65
66 AstNodeContent::ReturnStatement(ret) => handle_return_statement(ret, changes),
67
68 AstNodeContent::Expression(expr) => handle_expression(expr, changes),
69
70 AstNodeContent::ImplicitReturnExpression(expr) => {
71 handle_implicit_return_expression(expr, changes)
72 }
73
74 AstNodeContent::UseStatement(_) => {
75 let next_span = &ast_node.span;
78 match changes.last() {
79 Some(last_change) => {
80 if last_change.start != next_span.start() {
81 changes.push(Change::new(next_span, ChangeType::UseStatement));
82 }
83 }
84 _ => changes.push(Change::new(next_span, ChangeType::UseStatement)),
85 }
86 }
87
88 AstNodeContent::IncludeStatement(_) => {
89 changes.push(Change::new(&ast_node.span, ChangeType::IncludeStatement))
90 }
91 }
92}
93
94fn handle_return_statement(ret: &ReturnStatement, changes: &mut Vec<Change>) {
95 handle_expression(&ret.expr, changes)
96}
97
98fn handle_declaration(dec: &Declaration, ast_node: &AstNode, changes: &mut Vec<Change>) {
99 match &dec {
100 Declaration::VariableDeclaration(var_dec) => handle_expression(&var_dec.body, changes),
101
102 Declaration::StructDeclaration(_) | Declaration::StorageDeclaration(_) => {
103 changes.push(Change::new(&ast_node.span, ChangeType::Struct))
104 }
105
106 Declaration::EnumDeclaration(_) => {
107 changes.push(Change::new(&ast_node.span, ChangeType::Enum))
108 }
109
110 Declaration::FunctionDeclaration(func) => {
111 for content in &func.body.contents {
112 traverse_ast_node(content, changes);
113 }
114 }
115
116 Declaration::ImplSelf(impl_self) => {
117 for func in &impl_self.functions {
118 for content in &func.body.contents {
119 traverse_ast_node(content, changes);
120 }
121 }
122 }
123 Declaration::ImplTrait(impl_trait) => {
124 for func in &impl_trait.functions {
125 for content in &func.body.contents {
126 traverse_ast_node(content, changes);
127 }
128 }
129 }
130 _ => {}
131 };
132}
133
134fn handle_expression(expr: &Expression, changes: &mut Vec<Change>) {
135 let span = &expr.span;
136 match &expr.kind {
137 ExpressionKind::Struct(_) => changes.push(Change::new(span, ChangeType::Struct)),
138 ExpressionKind::If(IfExpression {
139 condition: _,
140 then,
141 r#else,
142 }) => {
143 handle_expression(then, changes);
144
145 if let Some(else_expr) = r#else {
146 handle_expression(else_expr, changes);
147 }
148 }
149 ExpressionKind::CodeBlock(contents) => {
150 for content in &contents.contents {
151 traverse_ast_node(content, changes);
152 }
153 }
154 ExpressionKind::DelineatedPath(_) => {
155 changes.push(Change::new(span, ChangeType::DelineatedPath));
156 }
157 _ => {}
158 }
159}
160
161fn handle_implicit_return_expression(expr: &Expression, changes: &mut Vec<Change>) {
162 handle_expression(expr, changes)
163}