25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

146 satır
8.0KB

  1. # E02-S04: check the diagnostic catalog, keep docs/diagnostics.md in sync with
  2. # it, build the diagnostics test PRG, and prepare a D81 with stale ERR files.
  3. # -UpdateDocs rewrites docs/diagnostics.md from src/common/diagcat.inc.
  4. [CmdletBinding()]
  5. param([switch]$UpdateDocs)
  6. $ErrorActionPreference = "Stop"
  7. $project = Split-Path $PSScriptRoot -Parent
  8. Import-Module (Join-Path $PSScriptRoot "lib\Nova128Test.psm1") -Force
  9. $out = Join-Path $project "build\diag-test"
  10. New-Item -ItemType Directory -Force -Path $out | Out-Null
  11. # ------------------------------------------------------------ the catalog
  12. $catalogPath = Join-Path $project "src\common\diagcat.inc"
  13. $catalog = @()
  14. foreach ($line in Get-Content -LiteralPath $catalogPath) {
  15. $m = [regex]::Match($line, '^\s*DIAGNOSTIC\s+(\w+),\s*(\d+),\s*"(.*)"\s*$')
  16. if ($m.Success) {
  17. $catalog += [pscustomobject]@{ Symbol = $m.Groups[1].Value; Code = [int]$m.Groups[2].Value
  18. Text = $m.Groups[3].Value }
  19. }
  20. }
  21. $ranges = @{
  22. SRC = @(, @(1, 19)); LEX = @(, @(1, 19)); SYN = @(, @(20, 59)); SEM = @(@(60, 79), @(150, 169))
  23. TYP = @(, @(80, 119)); ACC = @(, @(120, 129)); IFC = @(, @(130, 149)); DSK = @(, @(200, 219))
  24. RES = @(, @(220, 239))
  25. }
  26. $categories = [ordered]@{
  27. "Source and lexical" = @(1, 19); "Syntax" = @(20, 59); "Names and declarations" = @(60, 79)
  28. "Types" = @(80, 119); "Access" = @(120, 129); "Interfaces" = @(130, 149)
  29. "Methods and returns" = @(150, 169); "Disk" = @(200, 219); "Resource limits" = @(220, 239)
  30. }
  31. $problems = @()
  32. foreach ($d in $catalog) {
  33. $prefix = $d.Symbol.Split('_')[0]
  34. if (-not $ranges.ContainsKey($prefix)) { $problems += "$($d.Symbol): unknown category prefix" }
  35. elseif (-not ($ranges[$prefix] | Where-Object { $d.Code -ge $_[0] -and $d.Code -le $_[1] })) {
  36. $problems += "$($d.Symbol) = $($d.Code) is outside the $prefix range"
  37. }
  38. if ($d.Code -lt 1 -or $d.Code -gt 255) { $problems += "$($d.Symbol): code must be 1..255" }
  39. $argCount = ([regex]::Matches($d.Text, '%')).Count
  40. if ($argCount -gt 2) { $problems += "$($d.Symbol): more than two arguments" }
  41. if ($argCount -eq 0 -and $d.Text.Length -gt 39) { $problems += "$($d.Symbol): message longer than 39" }
  42. if ($d.Text -cmatch '[a-z]') { $problems += "$($d.Symbol): use uppercase ASCII (PETSCII unshifted)" }
  43. # ERR line <= 80 (Vim's width). Spec limits: name <= 15 ("12345678901
  44. # 2.N8"), line <= 599, column <= 81, so "Ennn NAME LLL CC " <= 28.
  45. if ((28 + $d.Text.Length - $argCount + 16 * $argCount) -gt 80) { $problems += "$($d.Symbol): ERR line can exceed 80" }
  46. }
  47. $dupes = $catalog | Group-Object Code | Where-Object Count -gt 1
  48. foreach ($g in $dupes) { $problems += "code $($g.Name) used by $(($g.Group.Symbol) -join ', ')" }
  49. $dupes = $catalog | Group-Object Symbol | Where-Object Count -gt 1
  50. foreach ($g in $dupes) { $problems += "symbol $($g.Name) declared twice" }
  51. foreach ($e in Get-ChildItem (Join-Path $project "tests\grammar\rejected") -Filter *.expect) {
  52. $sym = [regex]::Match((Get-Content -Raw $e.FullName), '(?m)^diagnostic: (\w+)').Groups[1].Value
  53. if (-not ($catalog | Where-Object Symbol -eq $sym)) { $problems += "$($e.Name): $sym is not in the catalog" }
  54. }
  55. if ($problems) { throw ("diagnostic catalog problems:`n " + ($problems -join "`n ")) }
  56. # ------------------------------------------------- docs/diagnostics.md
  57. $doc = New-Object System.Text.StringBuilder
  58. [void]$doc.AppendLine("# Nova128 Diagnostics")
  59. [void]$doc.AppendLine("")
  60. [void]$doc.AppendLine("Generated from ``src/common/diagcat.inc`` by ``scripts/build-diag-test.ps1 -UpdateDocs``.")
  61. [void]$doc.AppendLine("Do not edit by hand. Numbers are stable: never renumber or reuse one.")
  62. [void]$doc.AppendLine("")
  63. [void]$doc.AppendLine("Each ``%`` is replaced by an argument such as a name or type. On screen a")
  64. [void]$doc.AppendLine("diagnostic is two lines, the header and the message clipped to 39 characters:")
  65. [void]$doc.AppendLine("")
  66. [void]$doc.AppendLine('```text')
  67. [void]$doc.AppendLine("E010 TEST.N8 3 11")
  68. [void]$doc.AppendLine("CHARACTER LITERAL NEEDS ONE CHARACTER")
  69. [void]$doc.AppendLine('```')
  70. [void]$doc.AppendLine("")
  71. [void]$doc.AppendLine("``NAME.ERR`` holds one full line per diagnostic: ``E010 TEST.N8 3 11 CHARACTER ...``.")
  72. [void]$doc.AppendLine("It is scratched when compilation starts and created only if a diagnostic occurs.")
  73. [void]$doc.AppendLine("After 20 errors the next one is replaced by E221 and compilation stops.")
  74. foreach ($c in $categories.Keys) {
  75. $lo = $categories[$c][0]; $hi = $categories[$c][1]
  76. [void]$doc.AppendLine("")
  77. [void]$doc.AppendLine(("## {0} (E{1:D3}-E{2:D3})" -f $c, $lo, $hi))
  78. [void]$doc.AppendLine("")
  79. [void]$doc.AppendLine("| Code | Symbol | Message |")
  80. [void]$doc.AppendLine("|---|---|---|")
  81. foreach ($d in ($catalog | Where-Object { $_.Code -ge $lo -and $_.Code -le $hi } | Sort-Object Code)) {
  82. [void]$doc.AppendLine(("| E{0:D3} | ``{1}`` | {2} |" -f $d.Code, $d.Symbol, $d.Text.Replace('|', '\|')))
  83. }
  84. }
  85. $docPath = Join-Path $project "docs\diagnostics.md"
  86. $docText = $doc.ToString().Replace("`r`n", "`n")
  87. if ($UpdateDocs) { [IO.File]::WriteAllText($docPath, $docText) }
  88. elseif (-not (Test-Path $docPath) -or [IO.File]::ReadAllText($docPath) -ne $docText) {
  89. throw "docs/diagnostics.md is out of date; run build-diag-test.ps1 -UpdateDocs and review"
  90. }
  91. # -------------------------------------------------------- expectations
  92. function Format-Diag([string]$name, [int]$line, [int]$col, [string]$symbol, [string[]]$arguments = @()) {
  93. $d = $catalog | Where-Object Symbol -eq $symbol
  94. $msg = $d.Text # each % takes the next argument
  95. foreach ($a in $arguments) { $idx = $msg.IndexOf('%'); $msg = $msg.Substring(0, $idx) + $a + $msg.Substring($idx + 1) }
  96. $header = "E{0:D3} {1} {2} {3}" -f $d.Code, $name, $line, $col
  97. return [pscustomobject]@{ Header = $header; Message = $msg; ErrLine = "$header $msg" }
  98. }
  99. $phaseA = @(
  100. (Format-Diag "DIAG.N8" 3 11 "LEX_BAD_CHAR_LITERAL"),
  101. (Format-Diag "DIAG.N8" 599 80 "SYN_EXPECTED_END_PROGRAM"),
  102. (Format-Diag "DIAG.N8" 12 5 "SEM_DUPLICATE_NAME" @("COUNTER")),
  103. (Format-Diag "DIAG.N8" 40 17 "TYP_MISMATCH" @("INTEGER", "VERYLONGCLASSNAM")),
  104. (Format-Diag "DIAG.N8" 1 1 "DSK_SOURCE_UNREADABLE" @("62")),
  105. (Format-Diag "DIAG.N8" 65535 255 "SYN_EXPECTED_RPAREN"))
  106. $phaseD = @(
  107. (Format-Diag "BAD*.N8" 7 3 "LEX_INVALID_CHAR"),
  108. (Format-Diag "BAD*.N8" 7 3 "DSK_ERR_FILE_UNWRITABLE" @("##")), # ## = DOS code, checked by pattern
  109. (Format-Diag "BAD*.N8" 8 4 "LEX_INVALID_CHAR"))
  110. $limit = @(1..20 | ForEach-Object { (Format-Diag "LIMIT.N8" $_ 1 "LEX_INVALID_CHAR").ErrLine })
  111. $limit += (Format-Diag "LIMIT.N8" 21 1 "RES_ERROR_LIMIT").ErrLine
  112. $screen = @()
  113. foreach ($d in ($phaseA + $phaseD)) {
  114. $screen += $d.Header
  115. $screen += $(if ($d.Message.Length -gt 39) { $d.Message.Substring(0, 39) } else { $d.Message })
  116. }
  117. $screen += "NOVA128 DIAG TEST OK"
  118. [ordered]@{
  119. diag = @($phaseA | ForEach-Object ErrLine)
  120. limit = $limit
  121. screen = $screen
  122. } | ConvertTo-Json -Depth 3 | Set-Content (Join-Path $out "expected.json")
  123. # ------------------------------------------------------------- program
  124. $link = Invoke-Nova128Link -Name "diag-test" -BuildDir $out `
  125. -Config (Join-Path $project "cfg\compiler.cfg") -Sources @(
  126. (Join-Path $project "src\compiler\mmu.s"),
  127. (Join-Path $project "src\compiler\diskio.s"),
  128. (Join-Path $project "src\compiler\diagnostics.s"),
  129. (Join-Path $project "tests\diag\diag-test.s"))
  130. if ((Get-Nova128Label $link.Labels "test_entry") -ne 0x1C0D) { throw "test_entry is not at `$1C0D" }
  131. $stale = Join-Path $out "stale.pet"
  132. [IO.File]::WriteAllBytes($stale, [byte[]](0x53, 0x54, 0x41, 0x4C, 0x45, 0x0D)) # "STALE"
  133. New-Nova128Disk -Path (Join-Path $out "diag-test.d81") -Files @(
  134. @{ Name = "diag-test"; Path = $link.Program; Type = "prg" },
  135. @{ Name = "diag.err"; Path = $stale; Type = "seq" },
  136. @{ Name = "limit.err"; Path = $stale; Type = "seq" },
  137. @{ Name = "clean.err"; Path = $stale; Type = "seq" })
  138. Write-Host ("catalog: {0} diagnostics in range; docs/diagnostics.md in sync" -f $catalog.Count)
  139. Write-Host ("built {0}" -f $link.Program)

Powered by TurnKey Linux.