v4 / .github / workflows / windows_ci_msvc.yml
679 lines · 607 sloc · 33.78 KB · c0624b274a458fe3e487d89ae9554c2e8c25bdb6
Raw
1name: CI Windows MSVC
2
3on:
4 push:
5 branches:
6 - master
7 paths-ignore:
8 - '**.md'
9 - '**.yml'
10 - '!**.bat'
11 - '!**/windows_ci_msvc.yml'
12 - 'cmd/tools/**'
13 - '!cmd/tools/builders/**.v'
14 pull_request:
15 paths-ignore:
16 - '**.md'
17 - '**.yml'
18 - '!**.bat'
19 - '!**/windows_ci_msvc.yml'
20 - '!**/windows-install-sqlite.bat'
21 - 'cmd/tools/**'
22 - '!cmd/tools/builders/**.v'
23
24concurrency:
25 group: windows-${{ github.workflow }}-${{ github.ref == 'refs/heads/master' && github.sha || github.ref }}
26 cancel-in-progress: true
27
28jobs:
29 msvc-windows:
30 runs-on: windows-2022
31 timeout-minutes: 70
32 env:
33 VFLAGS: -cc msvc
34 VTEST_SHOW_LONGEST_BY_RUNTIME: 3
35 VTEST_SHOW_LONGEST_BY_COMPTIME: 3
36 VTEST_SHOW_LONGEST_BY_TOTALTIME: 3
37 steps:
38 - uses: actions/checkout@v7
39 - uses: ilammy/msvc-dev-cmd@v1
40 with:
41 arch: x64
42 - name: Verify MSVC tools
43 run: |
44 where.exe cl.exe
45 where.exe link.exe
46 where.exe dumpbin.exe
47 - name: Build
48 run: |
49 echo %VFLAGS%
50 echo $VFLAGS
51 .\makev.bat -msvc
52 .\v.exe symlink
53 - name: backend x64 regressions
54 if: ${{ false }} # Temporarily disabled.
55 run: |
56 function Assert-LastExit([string] $label) {
57 if ($LASTEXITCODE -ne 0) {
58 throw "$label failed with exit code $LASTEXITCODE"
59 }
60 }
61
62 $env:VJOBS = '1'
63 .\v.exe test `
64 vlib/v2_toberemoved/abi `
65 vlib/v2_toberemoved/gen/x64/x64_abi_test.v `
66 vlib/v2_toberemoved/gen/x64/x64_backend_diagnostics_test.v `
67 vlib/v2_toberemoved/gen/x64/x64_object_format_test.v `
68 vlib/v2_toberemoved/gen/x64/x64_pe_linker_test.v `
69 vlib/v2_toberemoved/ssa/tree_sumtype_lowering_test.v
70 Assert-LastExit 'stable V2 x64 unit tests'
71 .\v.exe test -run-only test_module_qualified_alias_array_field_index_has_alias_element_type,test_module_storage_legacy_direct_import_nested_module_selector_uses_declared_leaf_module,test_module_storage_flat_direct_import_nested_module_selector_uses_declared_leaf_module vlib/v2_toberemoved/ssa/module_storage_test.v
72 Assert-LastExit 'targeted vlib/v2_toberemoved/ssa/module_storage_test.v regressions'
73 .\v.exe test -run-only test_x64_macos_windows_math_log_20_stdout_exact_bytes,test_x64_macos_windows_generic_sumtype_repeated_base_specialization_stdout_exact_bytes,test_x64_macos_windows_formatted_int_interpolation_stdout_exact_bytes,test_x64_macos_windows_formatted_int_width_100_interpolation_stdout_exact_bytes,test_x64_macos_windows_formatted_f64_interpolation_stdout_exact_bytes,test_x64_macos_windows_formatted_string_return_lifetime_stdout_exact_bytes,test_x64_macos_windows_spectral_reduced_formatted_stdout_exact_bytes,test_x64_macos_windows_bits_len32_stdout_exact_bytes,test_x64_macos_windows_rand_u32n_interface_result_stdout_exact_bytes,test_x64_macos_windows_rand_intn_range_interface_result_stdout_exact_bytes,test_x64_macos_windows_textscanner_embedded_parser_stdout_exact_bytes,test_x64_macos_windows_struct_positional_side_effect_stdout_exact_bytes,test_x64_macos_windows_struct_named_side_effect_stdout_exact_bytes,test_x64_macos_windows_unrelated_same_shape_struct_stdout_exact_bytes,test_x64_macos_windows_named_init_embedded_value_stdout_exact_bytes,test_x64_macos_windows_get_raw_line_example_stdin_stdout_exact_bytes,test_x64_macos_windows_mini_calculator_example_stdin_stdout_exact_bytes,test_x64_macos_windows_mini_calculator_recursive_descent_example_stdin_stdout_exact_bytes vlib/v2_toberemoved/gen/x64/x64_runtime_smoke_test.v
74 Assert-LastExit 'reduced V2 x64 runtime smoke tests'
75 Remove-Item Env:\VJOBS -ErrorAction SilentlyContinue
76 .\v.exe test vlib/v2_toberemoved/builder/native_test.v vlib/v2_toberemoved/builder/target_os_test.v
77 Assert-LastExit 'vlib/v2_toberemoved/builder/native_test.v vlib/v2_toberemoved/builder/target_os_test.v'
78 .\v.exe test vlib/v2_toberemoved/ssa/optimize
79 Assert-LastExit 'vlib/v2_toberemoved/ssa/optimize'
80 $env:V2_VERIFY_STRICT = '1'
81 .\v.exe test vlib/v2_toberemoved/ssa/optimize
82 Assert-LastExit 'strict vlib/v2_toberemoved/ssa/optimize'
83 Remove-Item Env:\V2_VERIFY_STRICT -ErrorAction SilentlyContinue
84 - name: backend x64 examples
85 if: ${{ false }} # Temporarily disabled.
86 run: |
87 function Assert-LastExit([string] $label) {
88 if ($LASTEXITCODE -ne 0) {
89 throw "$label failed with exit code $LASTEXITCODE"
90 }
91 }
92
93 function Assert-ByteArrayEqual([byte[]] $actual, [byte[]] $expected, [string] $label) {
94 if ($actual.Length -ne $expected.Length) {
95 $actual_text = [System.Text.Encoding]::UTF8.GetString($actual)
96 $expected_text = [System.Text.Encoding]::UTF8.GetString($expected)
97 throw "$label mismatch. Expected length $($expected.Length), got $($actual.Length).`nExpected:`n$expected_text`nActual:`n$actual_text"
98 }
99 for ($i = 0; $i -lt $actual.Length; $i++) {
100 if ($actual[$i] -ne $expected[$i]) {
101 $actual_text = [System.Text.Encoding]::UTF8.GetString($actual)
102 $expected_text = [System.Text.Encoding]::UTF8.GetString($expected)
103 throw "$label mismatch at byte $i.`nExpected:`n$expected_text`nActual:`n$actual_text"
104 }
105 }
106 }
107
108 function Get-PeImportedDlls([string] $exe) {
109 $output = & dumpbin.exe /imports $exe 2>&1
110 if ($LASTEXITCODE -ne 0) {
111 $text = ($output | Out-String).Trim()
112 throw "dumpbin import inspection failed for $exe with exit code $LASTEXITCODE`n$text"
113 }
114
115 $dlls = [System.Collections.Generic.List[string]]::new()
116 foreach ($lineObject in $output) {
117 $line = [string] $lineObject
118 if ($line -match '^\s*([A-Za-z0-9_.-]+\.dll)\s*$') {
119 $dlls.Add($matches[1].ToLowerInvariant())
120 }
121 }
122 return $dlls | Sort-Object -Unique
123 }
124
125 function Assert-TinyPeImports([string] $name, [string] $exe, [string] $pe_import_mode) {
126 if ($pe_import_mode -eq '') {
127 return
128 }
129 if ($pe_import_mode -eq 'tiny-used') {
130 [string[]] $allowed_dlls = @('kernel32.dll')
131 } elseif ($pe_import_mode -eq 'tiny-shell32-argv') {
132 [string[]] $allowed_dlls = @('kernel32.dll', 'shell32.dll')
133 } else {
134 throw "$name has unknown PE import validation mode: $pe_import_mode"
135 }
136
137 [string[]] $dlls = @(Get-PeImportedDlls $exe)
138 if ($dlls.Count -eq 0) {
139 throw "$name PE import validation found no imported DLLs with dumpbin.exe"
140 }
141
142 $crt_dlls = $dlls | Where-Object {
143 $_ -match '^(msvcrt|ucrtbase|vcruntime)[0-9]*\.dll$' -or $_ -match '^api-ms-win-crt-.*\.dll$'
144 }
145 if ($crt_dlls.Count -gt 0) {
146 throw "$name tiny PE unexpectedly imports CRT DLL(s): $($crt_dlls -join ', ')"
147 }
148
149 $unexpected_dlls = $dlls | Where-Object { $_ -notin $allowed_dlls }
150 if ($unexpected_dlls.Count -gt 0) {
151 throw "$name PE imports unexpected DLL(s): $($unexpected_dlls -join ', ')"
152 }
153
154 $missing_dlls = $allowed_dlls | Where-Object { $_ -notin $dlls }
155 if ($missing_dlls.Count -gt 0) {
156 throw "$name PE import validation missed expected DLL(s): $($missing_dlls -join ', ')"
157 }
158 }
159
160 function Invoke-NativeX64Example([string] $source, [string] $name, [byte[]] $expected_stdout, [string] $pe_import_mode = '', [string[]] $program_args = @()) {
161 $exe = Join-Path $tmp "$name.exe"
162 $stdout_path = Join-Path $tmp "$name.out"
163 $stderr_path = Join-Path $tmp "$name.err"
164
165 $compile_output = & .\v.exe -v2 -no-parallel -b x64 $source -o $exe 2>&1
166 $compile_exit = $LASTEXITCODE
167 foreach ($line in $compile_output) {
168 Write-Host $line
169 }
170 if ($compile_exit -ne 0) {
171 throw "compile $source failed with exit code $compile_exit"
172 }
173 Assert-TinyPeImports $name $exe $pe_import_mode
174
175 Remove-Item -LiteralPath $stdout_path, $stderr_path -Force -ErrorAction SilentlyContinue
176 if ($program_args.Count -gt 0) {
177 $process = Start-Process -FilePath $exe -ArgumentList $program_args -NoNewWindow -Wait -PassThru -RedirectStandardOutput $stdout_path -RedirectStandardError $stderr_path
178 } else {
179 $process = Start-Process -FilePath $exe -NoNewWindow -Wait -PassThru -RedirectStandardOutput $stdout_path -RedirectStandardError $stderr_path
180 }
181 if ($process.ExitCode -ne 0) {
182 if (Test-Path -LiteralPath $stderr_path) {
183 Get-Content -LiteralPath $stderr_path
184 }
185 throw "$source exited with code $($process.ExitCode)"
186 }
187
188 [byte[]] $stdout = if (Test-Path -LiteralPath $stdout_path) { [System.IO.File]::ReadAllBytes($stdout_path) } else { New-Object byte[] 0 }
189 [byte[]] $stderr = if (Test-Path -LiteralPath $stderr_path) { [System.IO.File]::ReadAllBytes($stderr_path) } else { New-Object byte[] 0 }
190 $empty = New-Object byte[] 0
191 Assert-ByteArrayEqual $stdout $expected_stdout "$source stdout"
192 Assert-ByteArrayEqual $stderr $empty "$source stderr"
193 }
194
195 function Invoke-NativeX64ExampleWithStdin([string] $source, [string] $name, [byte[]] $expected_stdout, [string] $stdin_path, [string] $pe_import_mode = '', [string[]] $program_args = @()) {
196 $exe = Join-Path $tmp "$name.exe"
197 $stdout_path = Join-Path $tmp "$name.out"
198 $stderr_path = Join-Path $tmp "$name.err"
199
200 $compile_output = & .\v.exe -v2 -no-parallel -b x64 $source -o $exe 2>&1
201 $compile_exit = $LASTEXITCODE
202 foreach ($line in $compile_output) {
203 Write-Host $line
204 }
205 if ($compile_exit -ne 0) {
206 throw "compile $source failed with exit code $compile_exit"
207 }
208 Assert-TinyPeImports $name $exe $pe_import_mode
209
210 Remove-Item -LiteralPath $stdout_path, $stderr_path -Force -ErrorAction SilentlyContinue
211 if ($program_args.Count -gt 0) {
212 $process = Start-Process -FilePath $exe -ArgumentList $program_args -NoNewWindow -Wait -PassThru -RedirectStandardInput $stdin_path -RedirectStandardOutput $stdout_path -RedirectStandardError $stderr_path
213 } else {
214 $process = Start-Process -FilePath $exe -NoNewWindow -Wait -PassThru -RedirectStandardInput $stdin_path -RedirectStandardOutput $stdout_path -RedirectStandardError $stderr_path
215 }
216 if ($process.ExitCode -ne 0) {
217 if (Test-Path -LiteralPath $stderr_path) {
218 Get-Content -LiteralPath $stderr_path
219 }
220 throw "$source exited with code $($process.ExitCode)"
221 }
222
223 [byte[]] $stdout = if (Test-Path -LiteralPath $stdout_path) { [System.IO.File]::ReadAllBytes($stdout_path) } else { New-Object byte[] 0 }
224 [byte[]] $stderr = if (Test-Path -LiteralPath $stderr_path) { [System.IO.File]::ReadAllBytes($stderr_path) } else { New-Object byte[] 0 }
225 $empty = New-Object byte[] 0
226 Assert-ByteArrayEqual $stdout $expected_stdout "$source stdout"
227 Assert-ByteArrayEqual $stderr $empty "$source stderr"
228 }
229
230 function Invoke-NativeX64ExampleCapture([string] $source, [string] $name, [string[]] $program_args = @()) {
231 $exe = Join-Path $tmp "$name.exe"
232 $stdout_path = Join-Path $tmp "$name.out"
233 $stderr_path = Join-Path $tmp "$name.err"
234
235 $compile_output = & .\v.exe -v2 -no-parallel -b x64 $source -o $exe 2>&1
236 $compile_exit = $LASTEXITCODE
237 foreach ($line in $compile_output) {
238 Write-Host $line
239 }
240 if ($compile_exit -ne 0) {
241 throw "compile $source failed with exit code $compile_exit"
242 }
243
244 Remove-Item -LiteralPath $stdout_path, $stderr_path -Force -ErrorAction SilentlyContinue
245 if ($program_args.Count -gt 0) {
246 $process = Start-Process -FilePath $exe -ArgumentList $program_args -NoNewWindow -Wait -PassThru -RedirectStandardOutput $stdout_path -RedirectStandardError $stderr_path
247 } else {
248 $process = Start-Process -FilePath $exe -NoNewWindow -Wait -PassThru -RedirectStandardOutput $stdout_path -RedirectStandardError $stderr_path
249 }
250 if ($process.ExitCode -ne 0) {
251 if (Test-Path -LiteralPath $stderr_path) {
252 Get-Content -LiteralPath $stderr_path
253 }
254 throw "$source exited with code $($process.ExitCode)"
255 }
256
257 [byte[]] $stderr = if (Test-Path -LiteralPath $stderr_path) { [System.IO.File]::ReadAllBytes($stderr_path) } else { New-Object byte[] 0 }
258 $empty = New-Object byte[] 0
259 Assert-ByteArrayEqual $stderr $empty "$source stderr"
260 return $stdout_path
261 }
262
263 function Assert-RandomIpsStdout([string] $path) {
264 [string[]] $lines = [System.IO.File]::ReadAllLines($path)
265 if ($lines.Count -ne 10) {
266 throw "random_ips expected 10 lines, got $($lines.Count)"
267 }
268 $rows = [System.Collections.Generic.List[string]]::new()
269 $all_second_zero = $true
270 $all_fourth_zero = $true
271 foreach ($line in $lines) {
272 [string[]] $parts = $line.Split('.')
273 if ($parts.Count -ne 4) {
274 throw "random_ips invalid IPv4 shape: $line"
275 }
276 [int[]] $octets = @()
277 foreach ($part in $parts) {
278 if ($part -notmatch '^[0-9]+$') {
279 throw "random_ips non-numeric octet: $line"
280 }
281 $value = [int] $part
282 if ($value -lt 0 -or $value -gt 254) {
283 throw "random_ips octet out of range: $line"
284 }
285 $octets += $value
286 }
287 if ($octets[1] -ne 0) {
288 $all_second_zero = $false
289 }
290 if ($octets[3] -ne 0) {
291 $all_fourth_zero = $false
292 }
293 $rows.Add(($octets -join '.'))
294 }
295 if (($rows | Sort-Object -Unique).Count -lt 3) {
296 throw 'random_ips output has too little row diversity'
297 }
298 if ($all_second_zero -and $all_fourth_zero) {
299 throw 'random_ips suspicious old x.0.x.0 pattern'
300 }
301 }
302
303 function Assert-Rule110Stdout([string] $path, [int] $width) {
304 [string[]] $lines = [System.IO.File]::ReadAllLines($path)
305 $title = 'Rule 110 V Implementation'
306 $idx = -1
307 for ($i = 0; $i -lt $lines.Count; $i++) {
308 if ($lines[$i].Contains($title)) {
309 $idx = $i
310 break
311 }
312 }
313 if ($idx -lt 0) {
314 throw 'rule110 missing title'
315 }
316 [string[]] $generations = @()
317 if ($idx + 1 -lt $lines.Count) {
318 $generations = @($lines[($idx + 1)..($lines.Count - 1)])
319 }
320 if ($generations.Count -gt 0 -and $generations[0] -eq '') {
321 if ($generations.Count -eq 1) {
322 $generations = @()
323 } else {
324 $generations = @($generations[1..($generations.Count - 1)])
325 }
326 }
327 if ($generations.Count -ne $width) {
328 throw "rule110 expected $width generation lines, got $($generations.Count)"
329 }
330 $has_live_cell = $false
331 foreach ($line in $generations) {
332 if ($line.Length -ne $width) {
333 throw "rule110 generation line has width $($line.Length), expected $width`: '$line'"
334 }
335 if ($line -match '[^ *]') {
336 throw "rule110 invalid generation chars: '$line'"
337 }
338 if ($line.Contains('*')) {
339 $has_live_cell = $true
340 }
341 }
342 if (-not $has_live_cell) {
343 throw 'rule110 expected at least one live cell'
344 }
345 if (($generations | Sort-Object -Unique).Count -lt 3) {
346 throw 'rule110 expected at least 3 distinct generation lines'
347 }
348 }
349
350 $tmp = Join-Path $env:RUNNER_TEMP 'v2_x64_native'
351 New-Item -ItemType Directory -Force -Path $tmp | Out-Null
352
353 function Get-VRunExpectedBytes([string] $source, [string] $name, [string[]] $program_args = @()) {
354 $stdout_path = Join-Path $tmp "$name.vrun.out"
355 $stderr_path = Join-Path $tmp "$name.vrun.err"
356 Remove-Item -LiteralPath $stdout_path, $stderr_path -Force -ErrorAction SilentlyContinue
357
358 $v_args = @('run', $source) + $program_args
359 $process = Start-Process -FilePath '.\v.exe' -ArgumentList $v_args -NoNewWindow -Wait -PassThru -RedirectStandardOutput $stdout_path -RedirectStandardError $stderr_path
360 if ($process.ExitCode -ne 0) {
361 if (Test-Path -LiteralPath $stderr_path) {
362 Get-Content -LiteralPath $stderr_path
363 }
364 throw "v run $source $($program_args -join ' ') failed with code $($process.ExitCode)"
365 }
366
367 [byte[]] $stderr = if (Test-Path -LiteralPath $stderr_path) { [System.IO.File]::ReadAllBytes($stderr_path) } else { New-Object byte[] 0 }
368 $empty = New-Object byte[] 0
369 Assert-ByteArrayEqual $stderr $empty "v run $source stderr"
370 return [System.IO.File]::ReadAllBytes($stdout_path)
371 }
372
373 function Get-VRunExpectedBytesWithStdin([string] $source, [string] $name, [string] $stdin_path, [string[]] $program_args = @()) {
374 $stdout_path = Join-Path $tmp "$name.vrun.out"
375 $stderr_path = Join-Path $tmp "$name.vrun.err"
376 Remove-Item -LiteralPath $stdout_path, $stderr_path -Force -ErrorAction SilentlyContinue
377
378 $v_args = @('run', $source) + $program_args
379 $process = Start-Process -FilePath '.\v.exe' -ArgumentList $v_args -NoNewWindow -Wait -PassThru -RedirectStandardInput $stdin_path -RedirectStandardOutput $stdout_path -RedirectStandardError $stderr_path
380 if ($process.ExitCode -ne 0) {
381 if (Test-Path -LiteralPath $stderr_path) {
382 Get-Content -LiteralPath $stderr_path
383 }
384 throw "v run $source $($program_args -join ' ') failed with code $($process.ExitCode)"
385 }
386
387 [byte[]] $stderr = if (Test-Path -LiteralPath $stderr_path) { [System.IO.File]::ReadAllBytes($stderr_path) } else { New-Object byte[] 0 }
388 $empty = New-Object byte[] 0
389 Assert-ByteArrayEqual $stderr $empty "v run $source stderr"
390 return [System.IO.File]::ReadAllBytes($stdout_path)
391 }
392
393 $hello_expected = [System.Text.Encoding]::UTF8.GetBytes("Hello, World!`n")
394 Invoke-NativeX64Example 'examples/hello_world.v' 'hello_world' $hello_expected 'tiny-used'
395
396 $fizz_lines = 1..100 | ForEach-Object {
397 if ($_ % 15 -eq 0) {
398 'FizzBuzz'
399 } elseif ($_ % 3 -eq 0) {
400 'Fizz'
401 } elseif ($_ % 5 -eq 0) {
402 'Buzz'
403 } else {
404 [string] $_
405 }
406 }
407 $fizz_expected = [System.Text.Encoding]::UTF8.GetBytes(($fizz_lines -join "`n") + "`n")
408 Invoke-NativeX64Example 'examples/fizz_buzz.v' 'fizz_buzz' $fizz_expected 'tiny-used'
409
410 $fibonacci_expected = [System.Text.Encoding]::UTF8.GetBytes("1`n1`n2`n3`n5`n8`n13`n21`n34`n55`n89`n")
411 Invoke-NativeX64Example 'examples/fibonacci.v' 'fibonacci' $fibonacci_expected 'tiny-shell32-argv' @('10')
412
413 $dump_factorial_expected = [System.Text.Encoding]::UTF8.GetBytes("120`n")
414 Invoke-NativeX64Example 'examples/dump_factorial.v' 'dump_factorial' $dump_factorial_expected 'tiny-used'
415
416 function Get-HanoiExpectedLines([int] $n, [string] $a, [string] $b, [string] $c) {
417 if ($n -eq 1) {
418 "Disc 1 from $a to $c..."
419 return
420 }
421 Get-HanoiExpectedLines ($n - 1) $a $c $b
422 "Disc $n from $a to $c..."
423 Get-HanoiExpectedLines ($n - 1) $b $a $c
424 }
425
426 $hanoi_lines = @(Get-HanoiExpectedLines 7 'A' 'B' 'C')
427 $hanoi_expected = [System.Text.Encoding]::UTF8.GetBytes(($hanoi_lines -join "`n") + "`n")
428 Invoke-NativeX64Example 'examples/hanoi.v' 'hanoi' $hanoi_expected 'tiny-used'
429
430 function Get-SudokuExpectedLines {
431 $puzzle = @(
432 ,@(0, 3, 0, 0, 7, 0, 0, 0, 0)
433 ,@(0, 0, 0, 1, 3, 5, 0, 0, 0)
434 ,@(0, 0, 1, 0, 0, 0, 0, 5, 0)
435 ,@(1, 0, 0, 0, 6, 0, 0, 0, 3)
436 ,@(4, 0, 0, 8, 0, 3, 0, 0, 1)
437 ,@(7, 0, 0, 0, 2, 0, 0, 0, 6)
438 ,@(0, 0, 0, 0, 0, 0, 2, 1, 0)
439 ,@(0, 0, 0, 4, 1, 2, 0, 0, 5)
440 ,@(0, 0, 0, 0, 0, 0, 0, 7, 4)
441 )
442 $solution = @(
443 ,@(2, 3, 5, 6, 7, 8, 1, 4, 9)
444 ,@(9, 4, 7, 1, 3, 5, 8, 6, 2)
445 ,@(6, 8, 1, 2, 4, 9, 3, 5, 7)
446 ,@(1, 2, 8, 7, 6, 4, 5, 9, 3)
447 ,@(4, 5, 6, 8, 9, 3, 7, 2, 1)
448 ,@(7, 9, 3, 5, 2, 1, 4, 8, 6)
449 ,@(3, 6, 4, 9, 5, 7, 2, 1, 8)
450 ,@(8, 7, 9, 4, 1, 2, 6, 3, 5)
451 ,@(5, 1, 2, 3, 8, 6, 9, 7, 4)
452 )
453 $lines = [System.Collections.Generic.List[string]]::new()
454
455 function Add-SudokuGrid([string] $label, [object[]] $grid) {
456 $lines.Add($label)
457 for ($i = 0; $i -lt $grid.Count; $i++) {
458 if ($i % 3 -eq 0 -and $i -ne 0) {
459 $lines.Add('- - - - - - - - - - - -')
460 }
461 $line = ''
462 for ($j = 0; $j -lt $grid[$i].Count; $j++) {
463 if ($j % 3 -eq 0 -and $j -ne 0) {
464 $line += ' | '
465 }
466 $line += "$($grid[$i][$j]) "
467 }
468 $lines.Add($line)
469 }
470 }
471
472 Add-SudokuGrid 'Sudoku Puzzle:' $puzzle
473 $lines.Add('Solving...')
474 Add-SudokuGrid 'Solution:' $solution
475 return $lines.ToArray()
476 }
477
478 $sudoku_lines = @(Get-SudokuExpectedLines)
479 $sudoku_expected = [System.Text.Encoding]::UTF8.GetBytes(($sudoku_lines -join "`n") + "`n")
480 if ($sudoku_expected.Length -ne 582) {
481 throw "sudoku stdout oracle shape changed: $($sudoku_expected.Length) bytes"
482 }
483 Invoke-NativeX64Example 'examples/sudoku.v' 'sudoku' $sudoku_expected
484
485 $function_types_expected = [System.Text.Encoding]::UTF8.GetBytes("HELLO WORLD`nHELLO WORLD`nHELLO WORLD`n")
486 Invoke-NativeX64Example 'examples/function_types.v' 'function_types' $function_types_expected
487
488 $submodule_expected = [System.Text.Encoding]::UTF8.GetBytes("5`n3`n")
489 Invoke-NativeX64Example 'examples/submodule/main.v' 'submodule' $submodule_expected 'tiny-used'
490
491 function Get-TreeOfNodesExpectedLines {
492 @(
493 'tree structure:'
494 ' Node{'
495 ' value: 10'
496 ' left: Tree(Node{'
497 ' value: 30'
498 ' left: Tree(Empty{})'
499 ' right: Tree(Empty{})'
500 ' })'
501 ' right: Tree(Node{'
502 ' value: 20'
503 ' left: Tree(Empty{})'
504 ' right: Tree(Empty{})'
505 ' })'
506 '}'
507 'tree size: 3'
508 )
509 }
510
511 $tree_of_nodes_lines = @(Get-TreeOfNodesExpectedLines)
512 $tree_of_nodes_expected = [System.Text.Encoding]::UTF8.GetBytes(($tree_of_nodes_lines -join "`n") + "`n")
513 if ($tree_of_nodes_expected.Length -ne 259) {
514 throw "tree_of_nodes stdout oracle shape changed: $($tree_of_nodes_expected.Length) bytes"
515 }
516 Invoke-NativeX64Example 'examples/tree_of_nodes.v' 'tree_of_nodes' $tree_of_nodes_expected
517
518 $js_hello_world_expected = [System.Text.Encoding]::UTF8.GetBytes("Hello from V.js (0)`nHello from V.js (1)`nHello from V.js (2)`n")
519 Invoke-NativeX64Example 'examples/js_hello_world.v' 'js_hello_world' $js_hello_world_expected 'tiny-used'
520
521 function Get-VSingleQuotedLiteralBytes([string] $literal) {
522 $bytes = [System.Collections.Generic.List[byte]]::new()
523 for ($i = 0; $i -lt $literal.Length; $i++) {
524 $ch = $literal[$i]
525 if ($ch -eq '\') {
526 $i++
527 if ($i -ge $literal.Length) {
528 throw 'unterminated escape in V single-quoted literal'
529 }
530 $escaped = $literal[$i]
531 switch ([int][char] $escaped) {
532 110 { [void] $bytes.Add(10) }
533 116 { [void] $bytes.Add(9) }
534 114 { [void] $bytes.Add(13) }
535 92 { [void] $bytes.Add(92) }
536 39 { [void] $bytes.Add(39) }
537 34 { [void] $bytes.Add(34) }
538 default {
539 foreach ($byte in [System.Text.Encoding]::UTF8.GetBytes([string] $escaped)) {
540 [void] $bytes.Add($byte)
541 }
542 }
543 }
544 } else {
545 foreach ($byte in [System.Text.Encoding]::UTF8.GetBytes([string] $ch)) {
546 [void] $bytes.Add($byte)
547 }
548 }
549 }
550 return $bytes.ToArray()
551 }
552
553 function Get-VasciiExpectedBytes() {
554 $source = [System.IO.File]::ReadAllText((Join-Path (Get-Location) 'examples/vascii.v'), [System.Text.Encoding]::UTF8)
555 $start_marker = "println('"
556 $end_marker = "')"
557 $first = $source.IndexOf($start_marker, [System.StringComparison]::Ordinal)
558 if ($first -lt 0) {
559 throw 'missing vascii println literal start'
560 }
561 $second = $source.IndexOf($start_marker, $first + $start_marker.Length, [System.StringComparison]::Ordinal)
562 if ($second -ne -1) {
563 throw 'vascii stdout oracle expects one single-quoted println literal'
564 }
565 $start = $first + $start_marker.Length
566 $end = $source.LastIndexOf($end_marker, [System.StringComparison]::Ordinal)
567 if ($end -lt $start) {
568 throw 'missing vascii println literal end'
569 }
570 if ($source.Substring($end + $end_marker.Length).Trim() -ne '}') {
571 throw 'vascii stdout oracle expects the println literal to be the final main statement'
572 }
573 [byte[]] $bytes = Get-VSingleQuotedLiteralBytes ($source.Substring($start, $end - $start))
574 return $bytes + [byte] 10
575 }
576
577 [byte[]] $vascii_expected = Get-VasciiExpectedBytes
578 Invoke-NativeX64Example 'examples/vascii.v' 'vascii' $vascii_expected 'tiny-used'
579
580 [byte[]] $rune_expected = 0xF0, 0x9F, 0x98, 0x80, 0x0A, 0x40, 0x0A
581 Invoke-NativeX64Example 'examples/rune.v' 'rune' $rune_expected 'tiny-used'
582
583 [byte[]] $bfs_expected = Get-VRunExpectedBytes 'examples/graphs/bfs.v' 'bfs'
584 Invoke-NativeX64Example 'examples/graphs/bfs.v' 'bfs' $bfs_expected
585
586 [byte[]] $bfs3_expected = Get-VRunExpectedBytes 'examples/graphs/bfs3.v' 'bfs3'
587 Invoke-NativeX64Example 'examples/graphs/bfs3.v' 'bfs3' $bfs3_expected
588
589 [byte[]] $primes_expected = Get-VRunExpectedBytes 'examples/primes.v' 'primes' @('20')
590 Invoke-NativeX64Example 'examples/primes.v' 'primes' $primes_expected '' @('20')
591
592 [byte[]] $dfs_expected = Get-VRunExpectedBytes 'examples/graphs/dfs.v' 'dfs'
593 Invoke-NativeX64Example 'examples/graphs/dfs.v' 'dfs' $dfs_expected
594
595 [byte[]] $dijkstra_expected = Get-VRunExpectedBytes 'examples/graphs/dijkstra.v' 'dijkstra'
596 Invoke-NativeX64Example 'examples/graphs/dijkstra.v' 'dijkstra' $dijkstra_expected
597
598 [byte[]] $topological_sorting_greedy_expected = Get-VRunExpectedBytes 'examples/graphs/topological_sorting_greedy.v' 'topological_sorting_greedy'
599 Invoke-NativeX64Example 'examples/graphs/topological_sorting_greedy.v' 'topological_sorting_greedy' $topological_sorting_greedy_expected
600
601 [byte[]] $topological_sorting_dfs_expected = Get-VRunExpectedBytes 'examples/graphs/topological_sorting_dfs.v' 'topological_sorting_dfs'
602 Invoke-NativeX64Example 'examples/graphs/topological_sorting_dfs.v' 'topological_sorting_dfs' $topological_sorting_dfs_expected
603
604 [byte[]] $dfs2_expected = Get-VRunExpectedBytes 'examples/graphs/dfs2.v' 'dfs2'
605 Invoke-NativeX64Example 'examples/graphs/dfs2.v' 'dfs2' $dfs2_expected
606
607 [byte[]] $minimal_spann_tree_prim_expected = Get-VRunExpectedBytes 'examples/graphs/minimal_spann_tree_prim.v' 'minimal_spann_tree_prim'
608 Invoke-NativeX64Example 'examples/graphs/minimal_spann_tree_prim.v' 'minimal_spann_tree_prim' $minimal_spann_tree_prim_expected
609
610 [byte[]] $bellman_ford_expected = Get-VRunExpectedBytes 'examples/graphs/bellman-ford.v' 'bellman_ford'
611 Invoke-NativeX64Example 'examples/graphs/bellman-ford.v' 'bellman_ford' $bellman_ford_expected
612
613 [byte[]] $binary_search_tree_expected = Get-VRunExpectedBytes 'examples/binary_search_tree.v' 'binary_search_tree'
614 Invoke-NativeX64Example 'examples/binary_search_tree.v' 'binary_search_tree' $binary_search_tree_expected
615
616 # normal-required: IError/custom errors
617 [byte[]] $errors_expected = [System.Text.Encoding]::UTF8.GetBytes("wrong format`nempty input`n")
618 Invoke-NativeX64Example 'examples/errors.v' 'errors' $errors_expected
619
620 [byte[]] $custom_error_expected = Get-VRunExpectedBytes 'examples/custom_error.v' 'custom_error'
621 Invoke-NativeX64Example 'examples/custom_error.v' 'custom_error' $custom_error_expected
622
623 # normal-required: spectral norm/math.sqrt/formatted f64 interpolation
624 [byte[]] $spectral_expected = Get-VRunExpectedBytes 'examples/spectral.v' 'spectral' @('10')
625 Invoke-NativeX64Example 'examples/spectral.v' 'spectral' $spectral_expected '' @('10')
626
627 [byte[]] $quick_sort_expected = [System.Text.Encoding]::UTF8.GetBytes("length of random array is 1000`nbefore quick sort whether array is sorted: false`nafter quick sort whether array is sorted: true`n")
628 Invoke-NativeX64Example 'examples/quick_sort.v' 'quick_sort' $quick_sort_expected
629
630 $get_raw_line_input = Join-Path $tmp 'get_raw_line.in'
631 [System.IO.File]::WriteAllText($get_raw_line_input, "hello`nworld`n", [System.Text.UTF8Encoding]::new($false))
632 [byte[]] $get_raw_line_expected = Get-VRunExpectedBytesWithStdin 'examples/get_raw_line.v' 'get_raw_line' $get_raw_line_input
633 Invoke-NativeX64ExampleWithStdin 'examples/get_raw_line.v' 'get_raw_line' $get_raw_line_expected $get_raw_line_input
634
635 $mini_calculator_input = Join-Path $tmp 'mini_calculator.in'
636 [System.IO.File]::WriteAllText($mini_calculator_input, "3+4*2`nexit`n", [System.Text.UTF8Encoding]::new($false))
637 [byte[]] $mini_calculator_expected = Get-VRunExpectedBytesWithStdin 'examples/mini_calculator.v' 'mini_calculator' $mini_calculator_input
638 Invoke-NativeX64ExampleWithStdin 'examples/mini_calculator.v' 'mini_calculator' $mini_calculator_expected $mini_calculator_input
639
640 $mini_calculator_recursive_descent_input = Join-Path $tmp 'mini_calculator_recursive_descent.in'
641 [System.IO.File]::WriteAllText($mini_calculator_recursive_descent_input, "3+4*2`nexit`n", [System.Text.UTF8Encoding]::new($false))
642 [byte[]] $mini_calculator_recursive_descent_expected = Get-VRunExpectedBytesWithStdin 'examples/mini_calculator_recursive_descent.v' 'mini_calculator_recursive_descent' $mini_calculator_recursive_descent_input
643 Invoke-NativeX64ExampleWithStdin 'examples/mini_calculator_recursive_descent.v' 'mini_calculator_recursive_descent' $mini_calculator_recursive_descent_expected $mini_calculator_recursive_descent_input
644
645 $random_ips_stdout = Invoke-NativeX64ExampleCapture 'examples/random_ips.v' 'random_ips'
646 Assert-RandomIpsStdout $random_ips_stdout
647
648 $rule110_stdout = Invoke-NativeX64ExampleCapture 'examples/rule110.v' 'rule110' @('31')
649 Assert-Rule110Stdout $rule110_stdout 31
650 - name: Build V with WX
651 run: v -cflags /WX self
652 - name: All code is formatted
653 run: v -silent test-cleancode
654 - name: Test -cc msvc works
655 run: v -no-retry-compilation run examples/hello_world.v
656 - name: Install dependencies
657 run: |
658 v retry -- v setup-freetype
659 .\.github\workflows\windows-install-sqlite.bat
660 - name: v doctor
661 run: |
662 v doctor
663 - name: Verify `v test` works
664 run: |
665 echo $VFLAGS
666 v cmd/tools/test_if_v_test_system_works.v
667 ./cmd/tools/test_if_v_test_system_works
668 - name: Test pure V math module
669 run: v -silent -exclude @vlib/math/*.c.v test vlib/math/
670 - name: Self tests
671 run: v -silent test-self vlib
672 - name: Test v->js
673 run: v -o hi.js examples/js_hello_world.v && node hi.js
674 - name: Test v binaries
675 run: v build-vbinaries
676 - name: Build examples
677 run: v build-examples
678 - name: v2 self compilation
679 run: v -o v2.exe cmd/v && .\v2.exe -o v3.exe cmd/v
680