@@ -44,15 +44,14 @@ fn main() {
4444 content := os.read_file (file_path)!
4545 assert string_reproduces (content, error_msg, command)
4646 show_code_stats (content, label: 'Original code size' )
47- mut tree := parse (content)
4847
4948 // start tests
50- tmp_code := create_code (tree )
49+ tmp_code := create_code (parse (content) )
5150 assert string_reproduces (tmp_code, error_msg, command)
5251 show_code_stats (tmp_code, label: 'Code size without comments' )
5352
5453 // reduce the code
55- reduce_scope (mut tree , error_msg, command, do_fmt)
54+ reduce_scope (content , error_msg, command, do_fmt)
5655}
5756
5857// Return true if the command ran on the file produces the pattern
@@ -77,6 +76,7 @@ type Elem = string | Scope
7776@[heap]
7877struct Scope {
7978mut :
79+ fn_scope bool // contains a function (string: signature{}, children: function body)
8080 ignored bool // is the scope ignored when creating the file
8181 tmp_ignored bool // used when testing if it can be ignored in the file
8282 children []Elem // code blocks (strings & children scope
@@ -96,6 +96,24 @@ fn parse(file string) Scope { // The parser is surely incomplete for the V synta
9696 for file[i] != `\n ` { // comment -> skip until newline
9797 i++
9898 }
99+ } else if file[i] == `\n ` && file[i - 1 ] == `\n ` {
100+ i++ // remove excess newlines
101+ } else if file[i] == `\t ` {
102+ i++ // remove tabs for easier processing
103+ } else if file[i] == `f` && file[i + 1 ] == `n` && file[i + 2 ] == ` ` && file[i - 1 ] or {
104+ `\n `
105+ } == `\n ` {
106+ top.children << current_string
107+ // no increase in scope because not handled with {}
108+ current_string = ''
109+ top.children << & Scope{
110+ fn_scope: true
111+ }
112+ stack << & (top.children[top.children.len - 1 ] as Scope )
113+ current_string + = file[i].ascii_str () // f
114+ i++
115+ current_string + = file[i].ascii_str () // n
116+ i++
99117 } else if file[i] == `/` && file[i + 1 ] == `*` {
100118 i++
101119 i++
@@ -142,12 +160,23 @@ fn parse(file string) Scope { // The parser is surely incomplete for the V synta
142160 } else if file[i] == `}` {
143161 scope_level - = 1
144162 assert scope_level > = 0 , 'The scopes are not well detected ${stack [0 ]}'
145- top.children << current_string
163+ if current_string != '' {
164+ top.children << current_string
165+ }
166+ if stack.last ().children == [] {
167+ stack[stack.len - 2 ].children.delete (stack[stack.len - 2 ].children.len - 1 ) // delete the empty scope (the last children because top of the stack)
168+ }
146169 stack.pop ()
147170 top = stack[stack.len - 1 ]
148171 current_string = ''
149172 current_string + = file[i].ascii_str () // }
150173 i++
174+ if scope_level == 0 && stack.len == 2 { // the function and the body scope
175+ top.children << current_string
176+ stack.pop ()
177+ top = stack[stack.len - 1 ]
178+ current_string = ''
179+ }
151180 } else {
152181 current_string + = file[i].ascii_str ()
153182 i++
@@ -157,7 +186,7 @@ fn parse(file string) Scope { // The parser is surely incomplete for the V synta
157186 top = stack[stack.len - 1 ]
158187 top.children << current_string // last part of the file
159188 assert scope_level == 0 , 'The scopes are not well detected'
160- assert stack.len == 1 , 'The stack should only have the BODY scope'
189+ assert stack.len == 1 , 'The stack should only have the body scope'
161190 return * stack[0 ]
162191}
163192
@@ -183,101 +212,112 @@ fn create_code(sc Scope) string {
183212}
184213
185214// Reduces the code contained in the scope tree and writes the reduced code to `rpdc.v`
186- fn reduce_scope (mut sc Scope, error_msg string , command string , do_fmt bool ) {
215+ fn reduce_scope (content string , error_msg string , command string , do_fmt bool ) {
216+ mut sc := parse ('' ) // will get filled in the start of the loop
187217 println ('Cleaning the scopes' )
188- mut modified_smth := true // was a modification successful in reducing the code in the last iteration
189- for modified_smth { // as long as there are successful modifications
190- modified_smth = false
191- println ('NEXT ITERATION, loop 1' )
192- mut stack := []& Elem{}
193- for i in 0 .. sc.children.len {
194- stack << & sc.children[i]
195- }
196- for stack.len > 0 { // traverse the tree and disable (ignore) scopes that are not needed for reproduction
197- mut item := stack.pop ()
198- if mut item is Scope {
199- if ! item.ignored {
200- item.tmp_ignored = true // try to ignore it
201- code := create_code (sc)
202- item.tmp_ignored = false // dont need it anymore
203- if string_reproduces (code, error_msg, command) {
204- item.ignored = true
205- modified_smth = true
206- show_code_stats (code)
207- } else { // if can remove it, no need to go though it's children
208- for i in 0 .. item.children.len {
209- stack << & item.children[i]
218+ mut text_code := content
219+ mut outer_modified_smth := true
220+ for outer_modified_smth {
221+ sc = parse (text_code)
222+ outer_modified_smth = false
223+ mut modified_smth := true // was a modification successful in reducing the code in the last iteration
224+ for modified_smth { // as long as there are successful modifications
225+ modified_smth = false
226+ println ('NEXT ITERATION, loop 1' )
227+ mut stack := []& Elem{}
228+ for i in 0 .. sc.children.len {
229+ stack << & sc.children[i]
230+ }
231+ for stack.len > 0 { // traverse the tree and disable (ignore) scopes that are not needed for reproduction
232+ mut item := stack.pop ()
233+ if mut item is Scope {
234+ if ! item.ignored {
235+ item.tmp_ignored = true // try to ignore it
236+ code := create_code (sc)
237+ item.tmp_ignored = false // dont need it anymore
238+ if string_reproduces (code, error_msg, command) {
239+ item.ignored = true
240+ modified_smth = true
241+ outer_modified_smth = true
242+ show_code_stats (code)
243+ } else { // if can remove it, no need to go though it's children
244+ for i in 0 .. item.children.len {
245+ stack << & item.children[i]
246+ }
210247 }
211248 }
212249 }
213250 }
214251 }
215- }
216252
217- println ('Processing remaining lines' )
218- tmp_code := create_code (sc).split_into_lines () // dont forget to add back the \n
219- // Create the binary tree of the lines
220- depth := int (math.log2 (tmp_code.len)) + 1
221- mut c := 0
222- mut line_stack := []& Scope{}
223- line_stack << & Scope{}
224- for c < tmp_code.len {
225- l1 := line_stack.len
226- if l1 < = depth { // or equal because of the first node
227- if line_stack[l1 - 1 ].children.len < 2 {
228- line_stack[l1 - 1 ].children << & Scope{}
229- l2 := line_stack[l1 - 1 ].children.len
230- line_stack << & (line_stack[l1 - 1 ].children[l2 - 1 ] as Scope )
231- } else {
232- line_stack.pop ()
233- }
234- } else {
235- if line_stack[l1 - 1 ].children.len != 0 { // if there is already a string
236- line_stack.pop ()
253+ text_code = create_code (sc)
254+
255+ println ('Processing remaining lines' )
256+ split_code := text_code.split_into_lines () // dont forget to add back the \n
257+ // Create the binary tree of the lines
258+ depth := int (math.log2 (split_code.len)) + 1
259+ mut c := 0
260+ mut line_stack := []& Scope{}
261+ line_stack << & Scope{}
262+ for c < split_code.len {
263+ l1 := line_stack.len
264+ if l1 < = depth { // or equal because of the first node
265+ if line_stack[l1 - 1 ].children.len < 2 {
266+ line_stack[l1 - 1 ].children << & Scope{}
267+ l2 := line_stack[l1 - 1 ].children.len
268+ line_stack << & (line_stack[l1 - 1 ].children[l2 - 1 ] as Scope )
269+ } else {
270+ line_stack.pop ()
271+ }
237272 } else {
238- line_stack[l1 - 1 ].children << tmp_code[c] + '\n ' // the \n were removed by the split
239- c++
240- line_stack.pop () // already a string
273+ if line_stack[l1 - 1 ].children.len != 0 { // if there is already a string
274+ line_stack.pop ()
275+ } else {
276+ line_stack[l1 - 1 ].children << split_code[c] + '\n ' // the \n were removed by the split
277+ c++
278+ line_stack.pop () // already a string
279+ }
241280 }
242281 }
243- }
244282
245- // Traverse the tree and prune the useless lines / line groups for the reproduction
246- mut line_tree := * line_stack[0 ]
247- assert string_reproduces (create_code (line_tree), error_msg, command) // should be the same
248- println ('Pruning the lines/line groups' )
249- modified_smth = true
250- for modified_smth {
251- modified_smth = false
252- println ('NEXT ITERATION, loop 2' )
253- mut stack := []& Elem{}
254- for i in 0 .. line_tree.children.len {
255- stack << & line_tree.children[i]
256- }
257- for stack.len > 0 { // traverse the binary tree (of the lines)
258- mut item := stack.pop ()
259- if mut item is Scope {
260- if ! item.ignored {
261- item.tmp_ignored = true
262- code := create_code (line_tree)
263- item.tmp_ignored = false // dont need it anymore
264- if string_reproduces (code, error_msg, command) {
265- item.ignored = true
266- modified_smth = true
267- show_code_stats (code)
268- } else { // if can remove it, can remove it's children
269- for i in 0 .. item.children.len {
270- stack << & item.children[i]
283+ // Traverse the tree and prune the useless lines / line groups for the reproduction
284+ mut line_tree := * line_stack[0 ]
285+ assert string_reproduces (create_code (line_tree), error_msg, command) // should be the same
286+ println ('Pruning the lines/line groups' )
287+ modified_smth = true
288+ for modified_smth {
289+ modified_smth = false
290+ println ('NEXT ITERATION, loop 2' )
291+ mut stack := []& Elem{}
292+ for i in 0 .. line_tree.children.len {
293+ stack << & line_tree.children[i]
294+ }
295+ for stack.len > 0 { // traverse the binary tree (of the lines)
296+ mut item := stack.pop ()
297+ if mut item is Scope {
298+ if ! item.ignored {
299+ item.tmp_ignored = true
300+ code := create_code (line_tree)
301+ item.tmp_ignored = false // dont need it anymore
302+ if string_reproduces (code, error_msg, command) {
303+ item.ignored = true
304+ modified_smth = true
305+ outer_modified_smth = true
306+ show_code_stats (code)
307+ } else { // if can remove it, can remove it's children
308+ for i in 0 .. item.children.len {
309+ stack << & item.children[i]
310+ }
271311 }
272312 }
273313 }
274314 }
275315 }
316+ text_code = create_code (line_tree)
276317 }
277318
278- mre := create_code (line_tree) // final minimal reproductible example
279- assert string_reproduces (mre, error_msg, command)
280- os.write_file ('rpdc.v' , mre) or { panic (err) }
319+ assert string_reproduces (text_code, error_msg, command)
320+ os.write_file ('rpdc.v' , text_code) or { panic (err) }
281321 if do_fmt {
282322 os.execute ('v fmt -w rpdc.v' )
283323 final_content := os.read_file ('rpdc.v' ) or { panic (err) }
0 commit comments