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}