devalang_wasm/language/syntax/parser/driver/preprocessing.rs
1/// Preprocessing utilities for multiline statement merging
2
3/// Preprocess source to merge ALL multiline statements with braces
4/// Handles: synth, bind, pattern, let with map/array, emit, etc.
5/// Example:
6/// bind myMidi -> myBassline {
7/// velocity: 80,
8/// bpm: 150
9/// }
10/// becomes:
11/// bind myMidi -> myBassline { velocity: 80, bpm: 150 }
12pub fn preprocess_multiline_braces(source: &str) -> String {
13 let lines: Vec<&str> = source.lines().collect();
14 let mut result = Vec::new();
15 let mut i = 0;
16
17 while i < lines.len() {
18 let line = lines[i];
19 let trimmed = line.trim();
20
21 // Skip empty lines and comments
22 if trimmed.is_empty() || trimmed.starts_with("//") || trimmed.starts_with("#") {
23 result.push(line.to_string());
24 i += 1;
25 continue;
26 }
27
28 // Check if this line contains an opening brace
29 if line.contains('{') {
30 // Count braces to see if it's complete on one line
31 let open_braces = line.matches('{').count();
32 let close_braces = line.matches('}').count();
33
34 if open_braces > close_braces {
35 // Multiline detected - collect all lines until braces are balanced
36 let mut merged = line.to_string();
37 let mut brace_depth = open_braces - close_braces;
38 i += 1;
39
40 while i < lines.len() && brace_depth > 0 {
41 let next_line = lines[i];
42 let next_trimmed = next_line.trim();
43
44 // Skip comments inside multiline blocks
45 if next_trimmed.starts_with("//") || next_trimmed.starts_with("#") {
46 i += 1;
47 continue;
48 }
49
50 // Remove inline comments before merging
51 let clean_line = if let Some(comment_pos) = next_line.find("//") {
52 &next_line[..comment_pos]
53 } else if let Some(comment_pos) = next_line.find("#") {
54 &next_line[..comment_pos]
55 } else {
56 next_line
57 };
58
59 let clean_trimmed = clean_line.trim();
60 if !clean_trimmed.is_empty() {
61 // Add space before appending (unless it's a closing brace)
62 if !clean_trimmed.starts_with('}') && !merged.ends_with('{') {
63 merged.push(' ');
64 } else if clean_trimmed.starts_with('}') {
65 merged.push(' ');
66 }
67 merged.push_str(clean_trimmed);
68 }
69
70 // Update brace depth (use original line for brace counting)
71 brace_depth += next_line.matches('{').count();
72 brace_depth -= next_line.matches('}').count();
73
74 i += 1;
75 }
76
77 result.push(merged);
78 continue; // Don't increment i again
79 }
80 }
81
82 result.push(line.to_string());
83 i += 1;
84 }
85
86 result.join("\n")
87}
88
89/// Preprocess source to merge multiline arrow calls
90/// Example:
91/// target -> method1(arg)
92/// -> method2(arg)
93/// becomes:
94/// target -> method1(arg) -> method2(arg)
95pub fn preprocess_multiline_arrow_calls(source: &str) -> String {
96 let lines: Vec<&str> = source.lines().collect();
97 let mut result = Vec::new();
98 let mut i = 0;
99
100 while i < lines.len() {
101 let line = lines[i];
102 let trimmed = line.trim();
103
104 // Check if this line contains an arrow call but doesn't start with ->
105 if line.contains("->") && !trimmed.starts_with("->") {
106 // This is the start of a potential multiline arrow call
107 let mut merged = line.to_string();
108 i += 1;
109
110 // Merge all following lines that start with ->
111 while i < lines.len() {
112 let next_line = lines[i];
113 let next_trimmed = next_line.trim();
114
115 if next_trimmed.starts_with("->") {
116 // Append this line to the merged line
117 merged.push(' ');
118 merged.push_str(next_trimmed);
119 i += 1;
120 } else {
121 // Not a continuation line, stop merging
122 break;
123 }
124 }
125
126 result.push(merged);
127 continue; // Don't increment i again
128 }
129
130 result.push(line.to_string());
131 i += 1;
132 }
133
134 result.join("\n")
135}