v3: fix cmd/v compilation path #3499
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI Windows MSVC | |
| on: | |
| push: | |
| branches: | |
| - master | |
| paths-ignore: | |
| - '**.md' | |
| - '**.yml' | |
| - '!**.bat' | |
| - '!**/windows_ci_msvc.yml' | |
| - 'cmd/tools/**' | |
| - '!cmd/tools/builders/**.v' | |
| pull_request: | |
| paths-ignore: | |
| - '**.md' | |
| - '**.yml' | |
| - '!**.bat' | |
| - '!**/windows_ci_msvc.yml' | |
| - '!**/windows-install-sqlite.bat' | |
| - 'cmd/tools/**' | |
| - '!cmd/tools/builders/**.v' | |
| concurrency: | |
| group: windows-${{ github.workflow }}-${{ github.ref == 'refs/heads/master' && github.sha || github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| msvc-windows: | |
| runs-on: windows-2022 | |
| timeout-minutes: 70 | |
| env: | |
| VFLAGS: -cc msvc | |
| VTEST_SHOW_LONGEST_BY_RUNTIME: 3 | |
| VTEST_SHOW_LONGEST_BY_COMPTIME: 3 | |
| VTEST_SHOW_LONGEST_BY_TOTALTIME: 3 | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: ilammy/msvc-dev-cmd@v1 | |
| with: | |
| arch: x64 | |
| - name: Verify MSVC tools | |
| run: | | |
| where.exe cl.exe | |
| where.exe link.exe | |
| where.exe dumpbin.exe | |
| - name: Build | |
| run: | | |
| echo %VFLAGS% | |
| echo $VFLAGS | |
| .\makev.bat -msvc | |
| .\v.exe symlink | |
| - name: backend x64 regressions | |
| if: ${{ false }} # Temporarily disabled. | |
| run: | | |
| function Assert-LastExit([string] $label) { | |
| if ($LASTEXITCODE -ne 0) { | |
| throw "$label failed with exit code $LASTEXITCODE" | |
| } | |
| } | |
| $env:VJOBS = '1' | |
| .\v.exe test ` | |
| vlib/v2_toberemoved/abi ` | |
| vlib/v2_toberemoved/gen/x64/x64_abi_test.v ` | |
| vlib/v2_toberemoved/gen/x64/x64_backend_diagnostics_test.v ` | |
| vlib/v2_toberemoved/gen/x64/x64_object_format_test.v ` | |
| vlib/v2_toberemoved/gen/x64/x64_pe_linker_test.v ` | |
| vlib/v2_toberemoved/ssa/tree_sumtype_lowering_test.v | |
| Assert-LastExit 'stable V2 x64 unit tests' | |
| .\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 | |
| Assert-LastExit 'targeted vlib/v2_toberemoved/ssa/module_storage_test.v regressions' | |
| .\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 | |
| Assert-LastExit 'reduced V2 x64 runtime smoke tests' | |
| Remove-Item Env:\VJOBS -ErrorAction SilentlyContinue | |
| .\v.exe test vlib/v2_toberemoved/builder/native_test.v vlib/v2_toberemoved/builder/target_os_test.v | |
| Assert-LastExit 'vlib/v2_toberemoved/builder/native_test.v vlib/v2_toberemoved/builder/target_os_test.v' | |
| .\v.exe test vlib/v2_toberemoved/ssa/optimize | |
| Assert-LastExit 'vlib/v2_toberemoved/ssa/optimize' | |
| $env:V2_VERIFY_STRICT = '1' | |
| .\v.exe test vlib/v2_toberemoved/ssa/optimize | |
| Assert-LastExit 'strict vlib/v2_toberemoved/ssa/optimize' | |
| Remove-Item Env:\V2_VERIFY_STRICT -ErrorAction SilentlyContinue | |
| - name: backend x64 examples | |
| if: ${{ false }} # Temporarily disabled. | |
| run: | | |
| function Assert-LastExit([string] $label) { | |
| if ($LASTEXITCODE -ne 0) { | |
| throw "$label failed with exit code $LASTEXITCODE" | |
| } | |
| } | |
| function Assert-ByteArrayEqual([byte[]] $actual, [byte[]] $expected, [string] $label) { | |
| if ($actual.Length -ne $expected.Length) { | |
| $actual_text = [System.Text.Encoding]::UTF8.GetString($actual) | |
| $expected_text = [System.Text.Encoding]::UTF8.GetString($expected) | |
| throw "$label mismatch. Expected length $($expected.Length), got $($actual.Length).`nExpected:`n$expected_text`nActual:`n$actual_text" | |
| } | |
| for ($i = 0; $i -lt $actual.Length; $i++) { | |
| if ($actual[$i] -ne $expected[$i]) { | |
| $actual_text = [System.Text.Encoding]::UTF8.GetString($actual) | |
| $expected_text = [System.Text.Encoding]::UTF8.GetString($expected) | |
| throw "$label mismatch at byte $i.`nExpected:`n$expected_text`nActual:`n$actual_text" | |
| } | |
| } | |
| } | |
| function Get-PeImportedDlls([string] $exe) { | |
| $output = & dumpbin.exe /imports $exe 2>&1 | |
| if ($LASTEXITCODE -ne 0) { | |
| $text = ($output | Out-String).Trim() | |
| throw "dumpbin import inspection failed for $exe with exit code $LASTEXITCODE`n$text" | |
| } | |
| $dlls = [System.Collections.Generic.List[string]]::new() | |
| foreach ($lineObject in $output) { | |
| $line = [string] $lineObject | |
| if ($line -match '^\s*([A-Za-z0-9_.-]+\.dll)\s*$') { | |
| $dlls.Add($matches[1].ToLowerInvariant()) | |
| } | |
| } | |
| return $dlls | Sort-Object -Unique | |
| } | |
| function Assert-TinyPeImports([string] $name, [string] $exe, [string] $pe_import_mode) { | |
| if ($pe_import_mode -eq '') { | |
| return | |
| } | |
| if ($pe_import_mode -eq 'tiny-used') { | |
| [string[]] $allowed_dlls = @('kernel32.dll') | |
| } elseif ($pe_import_mode -eq 'tiny-shell32-argv') { | |
| [string[]] $allowed_dlls = @('kernel32.dll', 'shell32.dll') | |
| } else { | |
| throw "$name has unknown PE import validation mode: $pe_import_mode" | |
| } | |
| [string[]] $dlls = @(Get-PeImportedDlls $exe) | |
| if ($dlls.Count -eq 0) { | |
| throw "$name PE import validation found no imported DLLs with dumpbin.exe" | |
| } | |
| $crt_dlls = $dlls | Where-Object { | |
| $_ -match '^(msvcrt|ucrtbase|vcruntime)[0-9]*\.dll$' -or $_ -match '^api-ms-win-crt-.*\.dll$' | |
| } | |
| if ($crt_dlls.Count -gt 0) { | |
| throw "$name tiny PE unexpectedly imports CRT DLL(s): $($crt_dlls -join ', ')" | |
| } | |
| $unexpected_dlls = $dlls | Where-Object { $_ -notin $allowed_dlls } | |
| if ($unexpected_dlls.Count -gt 0) { | |
| throw "$name PE imports unexpected DLL(s): $($unexpected_dlls -join ', ')" | |
| } | |
| $missing_dlls = $allowed_dlls | Where-Object { $_ -notin $dlls } | |
| if ($missing_dlls.Count -gt 0) { | |
| throw "$name PE import validation missed expected DLL(s): $($missing_dlls -join ', ')" | |
| } | |
| } | |
| function Invoke-NativeX64Example([string] $source, [string] $name, [byte[]] $expected_stdout, [string] $pe_import_mode = '', [string[]] $program_args = @()) { | |
| $exe = Join-Path $tmp "$name.exe" | |
| $stdout_path = Join-Path $tmp "$name.out" | |
| $stderr_path = Join-Path $tmp "$name.err" | |
| $compile_output = & .\v.exe -v2 -no-parallel -b x64 $source -o $exe 2>&1 | |
| $compile_exit = $LASTEXITCODE | |
| foreach ($line in $compile_output) { | |
| Write-Host $line | |
| } | |
| if ($compile_exit -ne 0) { | |
| throw "compile $source failed with exit code $compile_exit" | |
| } | |
| Assert-TinyPeImports $name $exe $pe_import_mode | |
| Remove-Item -LiteralPath $stdout_path, $stderr_path -Force -ErrorAction SilentlyContinue | |
| if ($program_args.Count -gt 0) { | |
| $process = Start-Process -FilePath $exe -ArgumentList $program_args -NoNewWindow -Wait -PassThru -RedirectStandardOutput $stdout_path -RedirectStandardError $stderr_path | |
| } else { | |
| $process = Start-Process -FilePath $exe -NoNewWindow -Wait -PassThru -RedirectStandardOutput $stdout_path -RedirectStandardError $stderr_path | |
| } | |
| if ($process.ExitCode -ne 0) { | |
| if (Test-Path -LiteralPath $stderr_path) { | |
| Get-Content -LiteralPath $stderr_path | |
| } | |
| throw "$source exited with code $($process.ExitCode)" | |
| } | |
| [byte[]] $stdout = if (Test-Path -LiteralPath $stdout_path) { [System.IO.File]::ReadAllBytes($stdout_path) } else { New-Object byte[] 0 } | |
| [byte[]] $stderr = if (Test-Path -LiteralPath $stderr_path) { [System.IO.File]::ReadAllBytes($stderr_path) } else { New-Object byte[] 0 } | |
| $empty = New-Object byte[] 0 | |
| Assert-ByteArrayEqual $stdout $expected_stdout "$source stdout" | |
| Assert-ByteArrayEqual $stderr $empty "$source stderr" | |
| } | |
| function Invoke-NativeX64ExampleWithStdin([string] $source, [string] $name, [byte[]] $expected_stdout, [string] $stdin_path, [string] $pe_import_mode = '', [string[]] $program_args = @()) { | |
| $exe = Join-Path $tmp "$name.exe" | |
| $stdout_path = Join-Path $tmp "$name.out" | |
| $stderr_path = Join-Path $tmp "$name.err" | |
| $compile_output = & .\v.exe -v2 -no-parallel -b x64 $source -o $exe 2>&1 | |
| $compile_exit = $LASTEXITCODE | |
| foreach ($line in $compile_output) { | |
| Write-Host $line | |
| } | |
| if ($compile_exit -ne 0) { | |
| throw "compile $source failed with exit code $compile_exit" | |
| } | |
| Assert-TinyPeImports $name $exe $pe_import_mode | |
| Remove-Item -LiteralPath $stdout_path, $stderr_path -Force -ErrorAction SilentlyContinue | |
| if ($program_args.Count -gt 0) { | |
| $process = Start-Process -FilePath $exe -ArgumentList $program_args -NoNewWindow -Wait -PassThru -RedirectStandardInput $stdin_path -RedirectStandardOutput $stdout_path -RedirectStandardError $stderr_path | |
| } else { | |
| $process = Start-Process -FilePath $exe -NoNewWindow -Wait -PassThru -RedirectStandardInput $stdin_path -RedirectStandardOutput $stdout_path -RedirectStandardError $stderr_path | |
| } | |
| if ($process.ExitCode -ne 0) { | |
| if (Test-Path -LiteralPath $stderr_path) { | |
| Get-Content -LiteralPath $stderr_path | |
| } | |
| throw "$source exited with code $($process.ExitCode)" | |
| } | |
| [byte[]] $stdout = if (Test-Path -LiteralPath $stdout_path) { [System.IO.File]::ReadAllBytes($stdout_path) } else { New-Object byte[] 0 } | |
| [byte[]] $stderr = if (Test-Path -LiteralPath $stderr_path) { [System.IO.File]::ReadAllBytes($stderr_path) } else { New-Object byte[] 0 } | |
| $empty = New-Object byte[] 0 | |
| Assert-ByteArrayEqual $stdout $expected_stdout "$source stdout" | |
| Assert-ByteArrayEqual $stderr $empty "$source stderr" | |
| } | |
| function Invoke-NativeX64ExampleCapture([string] $source, [string] $name, [string[]] $program_args = @()) { | |
| $exe = Join-Path $tmp "$name.exe" | |
| $stdout_path = Join-Path $tmp "$name.out" | |
| $stderr_path = Join-Path $tmp "$name.err" | |
| $compile_output = & .\v.exe -v2 -no-parallel -b x64 $source -o $exe 2>&1 | |
| $compile_exit = $LASTEXITCODE | |
| foreach ($line in $compile_output) { | |
| Write-Host $line | |
| } | |
| if ($compile_exit -ne 0) { | |
| throw "compile $source failed with exit code $compile_exit" | |
| } | |
| Remove-Item -LiteralPath $stdout_path, $stderr_path -Force -ErrorAction SilentlyContinue | |
| if ($program_args.Count -gt 0) { | |
| $process = Start-Process -FilePath $exe -ArgumentList $program_args -NoNewWindow -Wait -PassThru -RedirectStandardOutput $stdout_path -RedirectStandardError $stderr_path | |
| } else { | |
| $process = Start-Process -FilePath $exe -NoNewWindow -Wait -PassThru -RedirectStandardOutput $stdout_path -RedirectStandardError $stderr_path | |
| } | |
| if ($process.ExitCode -ne 0) { | |
| if (Test-Path -LiteralPath $stderr_path) { | |
| Get-Content -LiteralPath $stderr_path | |
| } | |
| throw "$source exited with code $($process.ExitCode)" | |
| } | |
| [byte[]] $stderr = if (Test-Path -LiteralPath $stderr_path) { [System.IO.File]::ReadAllBytes($stderr_path) } else { New-Object byte[] 0 } | |
| $empty = New-Object byte[] 0 | |
| Assert-ByteArrayEqual $stderr $empty "$source stderr" | |
| return $stdout_path | |
| } | |
| function Assert-RandomIpsStdout([string] $path) { | |
| [string[]] $lines = [System.IO.File]::ReadAllLines($path) | |
| if ($lines.Count -ne 10) { | |
| throw "random_ips expected 10 lines, got $($lines.Count)" | |
| } | |
| $rows = [System.Collections.Generic.List[string]]::new() | |
| $all_second_zero = $true | |
| $all_fourth_zero = $true | |
| foreach ($line in $lines) { | |
| [string[]] $parts = $line.Split('.') | |
| if ($parts.Count -ne 4) { | |
| throw "random_ips invalid IPv4 shape: $line" | |
| } | |
| [int[]] $octets = @() | |
| foreach ($part in $parts) { | |
| if ($part -notmatch '^[0-9]+$') { | |
| throw "random_ips non-numeric octet: $line" | |
| } | |
| $value = [int] $part | |
| if ($value -lt 0 -or $value -gt 254) { | |
| throw "random_ips octet out of range: $line" | |
| } | |
| $octets += $value | |
| } | |
| if ($octets[1] -ne 0) { | |
| $all_second_zero = $false | |
| } | |
| if ($octets[3] -ne 0) { | |
| $all_fourth_zero = $false | |
| } | |
| $rows.Add(($octets -join '.')) | |
| } | |
| if (($rows | Sort-Object -Unique).Count -lt 3) { | |
| throw 'random_ips output has too little row diversity' | |
| } | |
| if ($all_second_zero -and $all_fourth_zero) { | |
| throw 'random_ips suspicious old x.0.x.0 pattern' | |
| } | |
| } | |
| function Assert-Rule110Stdout([string] $path, [int] $width) { | |
| [string[]] $lines = [System.IO.File]::ReadAllLines($path) | |
| $title = 'Rule 110 V Implementation' | |
| $idx = -1 | |
| for ($i = 0; $i -lt $lines.Count; $i++) { | |
| if ($lines[$i].Contains($title)) { | |
| $idx = $i | |
| break | |
| } | |
| } | |
| if ($idx -lt 0) { | |
| throw 'rule110 missing title' | |
| } | |
| [string[]] $generations = @() | |
| if ($idx + 1 -lt $lines.Count) { | |
| $generations = @($lines[($idx + 1)..($lines.Count - 1)]) | |
| } | |
| if ($generations.Count -gt 0 -and $generations[0] -eq '') { | |
| if ($generations.Count -eq 1) { | |
| $generations = @() | |
| } else { | |
| $generations = @($generations[1..($generations.Count - 1)]) | |
| } | |
| } | |
| if ($generations.Count -ne $width) { | |
| throw "rule110 expected $width generation lines, got $($generations.Count)" | |
| } | |
| $has_live_cell = $false | |
| foreach ($line in $generations) { | |
| if ($line.Length -ne $width) { | |
| throw "rule110 generation line has width $($line.Length), expected $width`: '$line'" | |
| } | |
| if ($line -match '[^ *]') { | |
| throw "rule110 invalid generation chars: '$line'" | |
| } | |
| if ($line.Contains('*')) { | |
| $has_live_cell = $true | |
| } | |
| } | |
| if (-not $has_live_cell) { | |
| throw 'rule110 expected at least one live cell' | |
| } | |
| if (($generations | Sort-Object -Unique).Count -lt 3) { | |
| throw 'rule110 expected at least 3 distinct generation lines' | |
| } | |
| } | |
| $tmp = Join-Path $env:RUNNER_TEMP 'v2_x64_native' | |
| New-Item -ItemType Directory -Force -Path $tmp | Out-Null | |
| function Get-VRunExpectedBytes([string] $source, [string] $name, [string[]] $program_args = @()) { | |
| $stdout_path = Join-Path $tmp "$name.vrun.out" | |
| $stderr_path = Join-Path $tmp "$name.vrun.err" | |
| Remove-Item -LiteralPath $stdout_path, $stderr_path -Force -ErrorAction SilentlyContinue | |
| $v_args = @('run', $source) + $program_args | |
| $process = Start-Process -FilePath '.\v.exe' -ArgumentList $v_args -NoNewWindow -Wait -PassThru -RedirectStandardOutput $stdout_path -RedirectStandardError $stderr_path | |
| if ($process.ExitCode -ne 0) { | |
| if (Test-Path -LiteralPath $stderr_path) { | |
| Get-Content -LiteralPath $stderr_path | |
| } | |
| throw "v run $source $($program_args -join ' ') failed with code $($process.ExitCode)" | |
| } | |
| [byte[]] $stderr = if (Test-Path -LiteralPath $stderr_path) { [System.IO.File]::ReadAllBytes($stderr_path) } else { New-Object byte[] 0 } | |
| $empty = New-Object byte[] 0 | |
| Assert-ByteArrayEqual $stderr $empty "v run $source stderr" | |
| return [System.IO.File]::ReadAllBytes($stdout_path) | |
| } | |
| function Get-VRunExpectedBytesWithStdin([string] $source, [string] $name, [string] $stdin_path, [string[]] $program_args = @()) { | |
| $stdout_path = Join-Path $tmp "$name.vrun.out" | |
| $stderr_path = Join-Path $tmp "$name.vrun.err" | |
| Remove-Item -LiteralPath $stdout_path, $stderr_path -Force -ErrorAction SilentlyContinue | |
| $v_args = @('run', $source) + $program_args | |
| $process = Start-Process -FilePath '.\v.exe' -ArgumentList $v_args -NoNewWindow -Wait -PassThru -RedirectStandardInput $stdin_path -RedirectStandardOutput $stdout_path -RedirectStandardError $stderr_path | |
| if ($process.ExitCode -ne 0) { | |
| if (Test-Path -LiteralPath $stderr_path) { | |
| Get-Content -LiteralPath $stderr_path | |
| } | |
| throw "v run $source $($program_args -join ' ') failed with code $($process.ExitCode)" | |
| } | |
| [byte[]] $stderr = if (Test-Path -LiteralPath $stderr_path) { [System.IO.File]::ReadAllBytes($stderr_path) } else { New-Object byte[] 0 } | |
| $empty = New-Object byte[] 0 | |
| Assert-ByteArrayEqual $stderr $empty "v run $source stderr" | |
| return [System.IO.File]::ReadAllBytes($stdout_path) | |
| } | |
| $hello_expected = [System.Text.Encoding]::UTF8.GetBytes("Hello, World!`n") | |
| Invoke-NativeX64Example 'examples/hello_world.v' 'hello_world' $hello_expected 'tiny-used' | |
| $fizz_lines = 1..100 | ForEach-Object { | |
| if ($_ % 15 -eq 0) { | |
| 'FizzBuzz' | |
| } elseif ($_ % 3 -eq 0) { | |
| 'Fizz' | |
| } elseif ($_ % 5 -eq 0) { | |
| 'Buzz' | |
| } else { | |
| [string] $_ | |
| } | |
| } | |
| $fizz_expected = [System.Text.Encoding]::UTF8.GetBytes(($fizz_lines -join "`n") + "`n") | |
| Invoke-NativeX64Example 'examples/fizz_buzz.v' 'fizz_buzz' $fizz_expected 'tiny-used' | |
| $fibonacci_expected = [System.Text.Encoding]::UTF8.GetBytes("1`n1`n2`n3`n5`n8`n13`n21`n34`n55`n89`n") | |
| Invoke-NativeX64Example 'examples/fibonacci.v' 'fibonacci' $fibonacci_expected 'tiny-shell32-argv' @('10') | |
| $dump_factorial_expected = [System.Text.Encoding]::UTF8.GetBytes("120`n") | |
| Invoke-NativeX64Example 'examples/dump_factorial.v' 'dump_factorial' $dump_factorial_expected 'tiny-used' | |
| function Get-HanoiExpectedLines([int] $n, [string] $a, [string] $b, [string] $c) { | |
| if ($n -eq 1) { | |
| "Disc 1 from $a to $c..." | |
| return | |
| } | |
| Get-HanoiExpectedLines ($n - 1) $a $c $b | |
| "Disc $n from $a to $c..." | |
| Get-HanoiExpectedLines ($n - 1) $b $a $c | |
| } | |
| $hanoi_lines = @(Get-HanoiExpectedLines 7 'A' 'B' 'C') | |
| $hanoi_expected = [System.Text.Encoding]::UTF8.GetBytes(($hanoi_lines -join "`n") + "`n") | |
| Invoke-NativeX64Example 'examples/hanoi.v' 'hanoi' $hanoi_expected 'tiny-used' | |
| function Get-SudokuExpectedLines { | |
| $puzzle = @( | |
| ,@(0, 3, 0, 0, 7, 0, 0, 0, 0) | |
| ,@(0, 0, 0, 1, 3, 5, 0, 0, 0) | |
| ,@(0, 0, 1, 0, 0, 0, 0, 5, 0) | |
| ,@(1, 0, 0, 0, 6, 0, 0, 0, 3) | |
| ,@(4, 0, 0, 8, 0, 3, 0, 0, 1) | |
| ,@(7, 0, 0, 0, 2, 0, 0, 0, 6) | |
| ,@(0, 0, 0, 0, 0, 0, 2, 1, 0) | |
| ,@(0, 0, 0, 4, 1, 2, 0, 0, 5) | |
| ,@(0, 0, 0, 0, 0, 0, 0, 7, 4) | |
| ) | |
| $solution = @( | |
| ,@(2, 3, 5, 6, 7, 8, 1, 4, 9) | |
| ,@(9, 4, 7, 1, 3, 5, 8, 6, 2) | |
| ,@(6, 8, 1, 2, 4, 9, 3, 5, 7) | |
| ,@(1, 2, 8, 7, 6, 4, 5, 9, 3) | |
| ,@(4, 5, 6, 8, 9, 3, 7, 2, 1) | |
| ,@(7, 9, 3, 5, 2, 1, 4, 8, 6) | |
| ,@(3, 6, 4, 9, 5, 7, 2, 1, 8) | |
| ,@(8, 7, 9, 4, 1, 2, 6, 3, 5) | |
| ,@(5, 1, 2, 3, 8, 6, 9, 7, 4) | |
| ) | |
| $lines = [System.Collections.Generic.List[string]]::new() | |
| function Add-SudokuGrid([string] $label, [object[]] $grid) { | |
| $lines.Add($label) | |
| for ($i = 0; $i -lt $grid.Count; $i++) { | |
| if ($i % 3 -eq 0 -and $i -ne 0) { | |
| $lines.Add('- - - - - - - - - - - -') | |
| } | |
| $line = '' | |
| for ($j = 0; $j -lt $grid[$i].Count; $j++) { | |
| if ($j % 3 -eq 0 -and $j -ne 0) { | |
| $line += ' | ' | |
| } | |
| $line += "$($grid[$i][$j]) " | |
| } | |
| $lines.Add($line) | |
| } | |
| } | |
| Add-SudokuGrid 'Sudoku Puzzle:' $puzzle | |
| $lines.Add('Solving...') | |
| Add-SudokuGrid 'Solution:' $solution | |
| return $lines.ToArray() | |
| } | |
| $sudoku_lines = @(Get-SudokuExpectedLines) | |
| $sudoku_expected = [System.Text.Encoding]::UTF8.GetBytes(($sudoku_lines -join "`n") + "`n") | |
| if ($sudoku_expected.Length -ne 582) { | |
| throw "sudoku stdout oracle shape changed: $($sudoku_expected.Length) bytes" | |
| } | |
| Invoke-NativeX64Example 'examples/sudoku.v' 'sudoku' $sudoku_expected | |
| $function_types_expected = [System.Text.Encoding]::UTF8.GetBytes("HELLO WORLD`nHELLO WORLD`nHELLO WORLD`n") | |
| Invoke-NativeX64Example 'examples/function_types.v' 'function_types' $function_types_expected | |
| $submodule_expected = [System.Text.Encoding]::UTF8.GetBytes("5`n3`n") | |
| Invoke-NativeX64Example 'examples/submodule/main.v' 'submodule' $submodule_expected 'tiny-used' | |
| function Get-TreeOfNodesExpectedLines { | |
| @( | |
| 'tree structure:' | |
| ' Node{' | |
| ' value: 10' | |
| ' left: Tree(Node{' | |
| ' value: 30' | |
| ' left: Tree(Empty{})' | |
| ' right: Tree(Empty{})' | |
| ' })' | |
| ' right: Tree(Node{' | |
| ' value: 20' | |
| ' left: Tree(Empty{})' | |
| ' right: Tree(Empty{})' | |
| ' })' | |
| '}' | |
| 'tree size: 3' | |
| ) | |
| } | |
| $tree_of_nodes_lines = @(Get-TreeOfNodesExpectedLines) | |
| $tree_of_nodes_expected = [System.Text.Encoding]::UTF8.GetBytes(($tree_of_nodes_lines -join "`n") + "`n") | |
| if ($tree_of_nodes_expected.Length -ne 259) { | |
| throw "tree_of_nodes stdout oracle shape changed: $($tree_of_nodes_expected.Length) bytes" | |
| } | |
| Invoke-NativeX64Example 'examples/tree_of_nodes.v' 'tree_of_nodes' $tree_of_nodes_expected | |
| $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") | |
| Invoke-NativeX64Example 'examples/js_hello_world.v' 'js_hello_world' $js_hello_world_expected 'tiny-used' | |
| function Get-VSingleQuotedLiteralBytes([string] $literal) { | |
| $bytes = [System.Collections.Generic.List[byte]]::new() | |
| for ($i = 0; $i -lt $literal.Length; $i++) { | |
| $ch = $literal[$i] | |
| if ($ch -eq '\') { | |
| $i++ | |
| if ($i -ge $literal.Length) { | |
| throw 'unterminated escape in V single-quoted literal' | |
| } | |
| $escaped = $literal[$i] | |
| switch ([int][char] $escaped) { | |
| 110 { [void] $bytes.Add(10) } | |
| 116 { [void] $bytes.Add(9) } | |
| 114 { [void] $bytes.Add(13) } | |
| 92 { [void] $bytes.Add(92) } | |
| 39 { [void] $bytes.Add(39) } | |
| 34 { [void] $bytes.Add(34) } | |
| default { | |
| foreach ($byte in [System.Text.Encoding]::UTF8.GetBytes([string] $escaped)) { | |
| [void] $bytes.Add($byte) | |
| } | |
| } | |
| } | |
| } else { | |
| foreach ($byte in [System.Text.Encoding]::UTF8.GetBytes([string] $ch)) { | |
| [void] $bytes.Add($byte) | |
| } | |
| } | |
| } | |
| return $bytes.ToArray() | |
| } | |
| function Get-VasciiExpectedBytes() { | |
| $source = [System.IO.File]::ReadAllText((Join-Path (Get-Location) 'examples/vascii.v'), [System.Text.Encoding]::UTF8) | |
| $start_marker = "println('" | |
| $end_marker = "')" | |
| $first = $source.IndexOf($start_marker, [System.StringComparison]::Ordinal) | |
| if ($first -lt 0) { | |
| throw 'missing vascii println literal start' | |
| } | |
| $second = $source.IndexOf($start_marker, $first + $start_marker.Length, [System.StringComparison]::Ordinal) | |
| if ($second -ne -1) { | |
| throw 'vascii stdout oracle expects one single-quoted println literal' | |
| } | |
| $start = $first + $start_marker.Length | |
| $end = $source.LastIndexOf($end_marker, [System.StringComparison]::Ordinal) | |
| if ($end -lt $start) { | |
| throw 'missing vascii println literal end' | |
| } | |
| if ($source.Substring($end + $end_marker.Length).Trim() -ne '}') { | |
| throw 'vascii stdout oracle expects the println literal to be the final main statement' | |
| } | |
| [byte[]] $bytes = Get-VSingleQuotedLiteralBytes ($source.Substring($start, $end - $start)) | |
| return $bytes + [byte] 10 | |
| } | |
| [byte[]] $vascii_expected = Get-VasciiExpectedBytes | |
| Invoke-NativeX64Example 'examples/vascii.v' 'vascii' $vascii_expected 'tiny-used' | |
| [byte[]] $rune_expected = 0xF0, 0x9F, 0x98, 0x80, 0x0A, 0x40, 0x0A | |
| Invoke-NativeX64Example 'examples/rune.v' 'rune' $rune_expected 'tiny-used' | |
| [byte[]] $bfs_expected = Get-VRunExpectedBytes 'examples/graphs/bfs.v' 'bfs' | |
| Invoke-NativeX64Example 'examples/graphs/bfs.v' 'bfs' $bfs_expected | |
| [byte[]] $bfs3_expected = Get-VRunExpectedBytes 'examples/graphs/bfs3.v' 'bfs3' | |
| Invoke-NativeX64Example 'examples/graphs/bfs3.v' 'bfs3' $bfs3_expected | |
| [byte[]] $primes_expected = Get-VRunExpectedBytes 'examples/primes.v' 'primes' @('20') | |
| Invoke-NativeX64Example 'examples/primes.v' 'primes' $primes_expected '' @('20') | |
| [byte[]] $dfs_expected = Get-VRunExpectedBytes 'examples/graphs/dfs.v' 'dfs' | |
| Invoke-NativeX64Example 'examples/graphs/dfs.v' 'dfs' $dfs_expected | |
| [byte[]] $dijkstra_expected = Get-VRunExpectedBytes 'examples/graphs/dijkstra.v' 'dijkstra' | |
| Invoke-NativeX64Example 'examples/graphs/dijkstra.v' 'dijkstra' $dijkstra_expected | |
| [byte[]] $topological_sorting_greedy_expected = Get-VRunExpectedBytes 'examples/graphs/topological_sorting_greedy.v' 'topological_sorting_greedy' | |
| Invoke-NativeX64Example 'examples/graphs/topological_sorting_greedy.v' 'topological_sorting_greedy' $topological_sorting_greedy_expected | |
| [byte[]] $topological_sorting_dfs_expected = Get-VRunExpectedBytes 'examples/graphs/topological_sorting_dfs.v' 'topological_sorting_dfs' | |
| Invoke-NativeX64Example 'examples/graphs/topological_sorting_dfs.v' 'topological_sorting_dfs' $topological_sorting_dfs_expected | |
| [byte[]] $dfs2_expected = Get-VRunExpectedBytes 'examples/graphs/dfs2.v' 'dfs2' | |
| Invoke-NativeX64Example 'examples/graphs/dfs2.v' 'dfs2' $dfs2_expected | |
| [byte[]] $minimal_spann_tree_prim_expected = Get-VRunExpectedBytes 'examples/graphs/minimal_spann_tree_prim.v' 'minimal_spann_tree_prim' | |
| Invoke-NativeX64Example 'examples/graphs/minimal_spann_tree_prim.v' 'minimal_spann_tree_prim' $minimal_spann_tree_prim_expected | |
| [byte[]] $bellman_ford_expected = Get-VRunExpectedBytes 'examples/graphs/bellman-ford.v' 'bellman_ford' | |
| Invoke-NativeX64Example 'examples/graphs/bellman-ford.v' 'bellman_ford' $bellman_ford_expected | |
| [byte[]] $binary_search_tree_expected = Get-VRunExpectedBytes 'examples/binary_search_tree.v' 'binary_search_tree' | |
| Invoke-NativeX64Example 'examples/binary_search_tree.v' 'binary_search_tree' $binary_search_tree_expected | |
| # normal-required: IError/custom errors | |
| [byte[]] $errors_expected = [System.Text.Encoding]::UTF8.GetBytes("wrong format`nempty input`n") | |
| Invoke-NativeX64Example 'examples/errors.v' 'errors' $errors_expected | |
| [byte[]] $custom_error_expected = Get-VRunExpectedBytes 'examples/custom_error.v' 'custom_error' | |
| Invoke-NativeX64Example 'examples/custom_error.v' 'custom_error' $custom_error_expected | |
| # normal-required: spectral norm/math.sqrt/formatted f64 interpolation | |
| [byte[]] $spectral_expected = Get-VRunExpectedBytes 'examples/spectral.v' 'spectral' @('10') | |
| Invoke-NativeX64Example 'examples/spectral.v' 'spectral' $spectral_expected '' @('10') | |
| [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") | |
| Invoke-NativeX64Example 'examples/quick_sort.v' 'quick_sort' $quick_sort_expected | |
| $get_raw_line_input = Join-Path $tmp 'get_raw_line.in' | |
| [System.IO.File]::WriteAllText($get_raw_line_input, "hello`nworld`n", [System.Text.UTF8Encoding]::new($false)) | |
| [byte[]] $get_raw_line_expected = Get-VRunExpectedBytesWithStdin 'examples/get_raw_line.v' 'get_raw_line' $get_raw_line_input | |
| Invoke-NativeX64ExampleWithStdin 'examples/get_raw_line.v' 'get_raw_line' $get_raw_line_expected $get_raw_line_input | |
| $mini_calculator_input = Join-Path $tmp 'mini_calculator.in' | |
| [System.IO.File]::WriteAllText($mini_calculator_input, "3+4*2`nexit`n", [System.Text.UTF8Encoding]::new($false)) | |
| [byte[]] $mini_calculator_expected = Get-VRunExpectedBytesWithStdin 'examples/mini_calculator.v' 'mini_calculator' $mini_calculator_input | |
| Invoke-NativeX64ExampleWithStdin 'examples/mini_calculator.v' 'mini_calculator' $mini_calculator_expected $mini_calculator_input | |
| $mini_calculator_recursive_descent_input = Join-Path $tmp 'mini_calculator_recursive_descent.in' | |
| [System.IO.File]::WriteAllText($mini_calculator_recursive_descent_input, "3+4*2`nexit`n", [System.Text.UTF8Encoding]::new($false)) | |
| [byte[]] $mini_calculator_recursive_descent_expected = Get-VRunExpectedBytesWithStdin 'examples/mini_calculator_recursive_descent.v' 'mini_calculator_recursive_descent' $mini_calculator_recursive_descent_input | |
| Invoke-NativeX64ExampleWithStdin 'examples/mini_calculator_recursive_descent.v' 'mini_calculator_recursive_descent' $mini_calculator_recursive_descent_expected $mini_calculator_recursive_descent_input | |
| $random_ips_stdout = Invoke-NativeX64ExampleCapture 'examples/random_ips.v' 'random_ips' | |
| Assert-RandomIpsStdout $random_ips_stdout | |
| $rule110_stdout = Invoke-NativeX64ExampleCapture 'examples/rule110.v' 'rule110' @('31') | |
| Assert-Rule110Stdout $rule110_stdout 31 | |
| - name: Build V with WX | |
| run: v -cflags /WX self | |
| - name: All code is formatted | |
| run: v -silent test-cleancode | |
| - name: Test -cc msvc works | |
| run: v -no-retry-compilation run examples/hello_world.v | |
| - name: Install dependencies | |
| run: | | |
| v retry -- v setup-freetype | |
| .\.github\workflows\windows-install-sqlite.bat | |
| - name: v doctor | |
| run: | | |
| v doctor | |
| - name: Verify `v test` works | |
| run: | | |
| echo $VFLAGS | |
| v cmd/tools/test_if_v_test_system_works.v | |
| ./cmd/tools/test_if_v_test_system_works | |
| - name: Test pure V math module | |
| run: v -silent -exclude @vlib/math/*.c.v test vlib/math/ | |
| - name: Self tests | |
| run: v -silent test-self vlib | |
| - name: Test v->js | |
| run: v -o hi.js examples/js_hello_world.v && node hi.js | |
| - name: Test v binaries | |
| run: v build-vbinaries | |
| - name: Build examples | |
| run: v build-examples | |
| - name: v2 self compilation | |
| run: v -o v2.exe cmd/v && .\v2.exe -o v3.exe cmd/v |