v / vlib / v2 / builder / flat_roundtrip_test.v
191 lines · 165 sloc · 3.49 KB · f3c5760b8838272e4789c38a1be9e03f9ceac351
Raw
1// Copyright (c) 2020-2024 Joe Conigliaro. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4// vtest build: macos
5module builder
6
7import os
8import v2.ast
9import v2.parser
10import v2.pref
11import v2.token
12
13fn parse_source_for_flat(src string) []ast.File {
14 tmp := '/tmp/v2_flat_roundtrip_${os.getpid()}.v'
15 os.write_file(tmp, src) or { panic('write_file: ${err}') }
16 defer {
17 os.rm(tmp) or {}
18 }
19 p := &pref.Preferences{}
20 mut fs := token.FileSet.new()
21 mut par := parser.Parser.new(p)
22 return par.parse_files([tmp], mut fs)
23}
24
25fn assert_roundtrip(src string) {
26 files := parse_source_for_flat(src)
27 flat_a := ast.flatten_files(files)
28 rt_files := flat_a.to_files()
29 flat_b := ast.flatten_files(rt_files)
30 sig_a := flat_a.signature()
31 sig_b := flat_b.signature()
32 if sig_a != sig_b {
33 mut diff_at := 0
34 for diff_at < sig_a.len && diff_at < sig_b.len && sig_a[diff_at] == sig_b[diff_at] {
35 diff_at++
36 }
37 from := if diff_at > 80 { diff_at - 80 } else { 0 }
38 end_a := if diff_at + 200 < sig_a.len { diff_at + 200 } else { sig_a.len }
39 end_b := if diff_at + 200 < sig_b.len { diff_at + 200 } else { sig_b.len }
40 eprintln('signature mismatch at offset ${diff_at}')
41 eprintln('A: ${sig_a[from..end_a]}')
42 eprintln('B: ${sig_b[from..end_b]}')
43 }
44 assert sig_a == sig_b, 'round-trip signature mismatch for source:\n${src}'
45}
46
47fn test_roundtrip_module_only() {
48 assert_roundtrip('module foo\n')
49}
50
51fn test_roundtrip_simple_fn() {
52 src := 'module main
53
54fn add(a int, b int) int {
55 return a + b
56}
57'
58 assert_roundtrip(src)
59}
60
61fn test_roundtrip_struct_and_const() {
62 src := "module main
63
64pub const greeting = 'hello'
65
66pub struct Point {
67pub mut:
68 x int
69 y int
70}
71
72fn (p Point) sum() int {
73 return p.x + p.y
74}
75"
76 assert_roundtrip(src)
77}
78
79fn test_roundtrip_control_flow() {
80 src := 'module main
81
82fn run(n int) int {
83 mut total := 0
84 for i := 0; i < n; i++ {
85 if i % 2 == 0 {
86 total += i
87 } else {
88 total -= i
89 }
90 }
91 return total
92}
93'
94 assert_roundtrip(src)
95}
96
97fn test_roundtrip_string_inter() {
98 src := "module main
99
100fn show(name string, age int) string {
101 return 'name=\${name} age=\${age:04d}'
102}
103"
104 assert_roundtrip(src)
105}
106
107fn test_roundtrip_match_and_array() {
108 src := 'module main
109
110fn classify(x int) string {
111 return match x {
112 0 { "zero" }
113 1, 2, 3 { "small" }
114 else { "big" }
115 }
116}
117
118fn sum_array() int {
119 nums := [1, 2, 3, 4, 5]
120 mut total := 0
121 for n in nums {
122 total += n
123 }
124 return total
125}
126'
127 assert_roundtrip(src)
128}
129
130fn test_roundtrip_map_and_or() {
131 src := "module main
132
133fn lookup() int {
134 m := {'a': 1, 'b': 2}
135 v := m['a'] or { -1 }
136 return v
137}
138"
139 assert_roundtrip(src)
140}
141
142fn test_roundtrip_enum_and_attrs() {
143 src := 'module main
144
145@[flag]
146pub enum Color {
147 red
148 green
149 blue
150}
151'
152 assert_roundtrip(src)
153}
154
155fn test_roundtrip_interface() {
156 src := 'module main
157
158pub interface Animal {
159 name() string
160mut:
161 age int
162}
163'
164 assert_roundtrip(src)
165}
166
167fn test_roundtrip_generic_fn() {
168 src := 'module main
169
170fn max[T](a T, b T) T {
171 if a > b { return a }
172 return b
173}
174'
175 assert_roundtrip(src)
176}
177
178fn test_roundtrip_real_source_file() {
179 // Round-trip a real V2 source file end-to-end. This exercises the full
180 // surface of parser-produced AST variants.
181 path := os.real_path('vlib/v2/ast/ast.v')
182 if !os.exists(path) {
183 return
184 }
185 src := os.read_file(path) or { return }
186 files := parse_source_for_flat(src)
187 flat_a := ast.flatten_files(files)
188 rt_files := flat_a.to_files()
189 flat_b := ast.flatten_files(rt_files)
190 assert flat_a.signature() == flat_b.signature(), 'round-trip mismatch for ${path}'
191}
192