|
| 1 | +#!/usr/bin/env rdmd |
| 2 | +/** |
| 3 | +Search HTML output for errors: |
| 4 | +- for undefined Ddoc macros |
| 5 | +- raw macro leakage |
| 6 | +- trailing parenthesis |
| 7 | +*/ |
| 8 | +import std.algorithm, std.file, std.functional, std.range, std.stdio; |
| 9 | + |
| 10 | +shared int errors = 0; |
| 11 | + |
| 12 | +void error(string name, string file, size_t lineNr, const(char)[] line) |
| 13 | +{ |
| 14 | + import core.atomic; |
| 15 | + errors.atomicOp!"+="(1); |
| 16 | + synchronized |
| 17 | + { |
| 18 | + stderr.writefln("%s:%d: [%s] %s", file, lineNr, name, line); |
| 19 | + } |
| 20 | +} |
| 21 | + |
| 22 | +enum ErrorMessages |
| 23 | +{ |
| 24 | + undefinedMacro = "UNDEFINED MACRO", |
| 25 | + rawMacroLeakage = "RAW MACRO LEAKAGE", |
| 26 | + trailingParenthesis = "TRAILING PARENTHESIS", |
| 27 | +} |
| 28 | + |
| 29 | +void checkLine(alias errorFun)(string file, size_t lineNr, const(char)[] line) |
| 30 | +{ |
| 31 | + if (line.canFind("UNDEFINED MACRO")) |
| 32 | + errorFun(ErrorMessages.undefinedMacro, file, lineNr, line); |
| 33 | + |
| 34 | + if (line.findSplitAfter("$(") |
| 35 | + .pipe!(a => !a.expand.only.any!empty && a[1].front != '\'')) |
| 36 | + errorFun(ErrorMessages.rawMacroLeakage, file, lineNr, line); |
| 37 | + |
| 38 | + if (line.equal(")")) |
| 39 | + errorFun(ErrorMessages.trailingParenthesis, file, lineNr, line); |
| 40 | +} |
| 41 | + |
| 42 | +version(unittest) {} else |
| 43 | +int main(string[] args) |
| 44 | +{ |
| 45 | + import std.parallelism : parallel; |
| 46 | + |
| 47 | + auto files = args[1 .. $]; |
| 48 | + foreach (file; files.parallel(1)) |
| 49 | + foreach (nr, line; File(file, "r").byLine.enumerate) |
| 50 | + checkLine!error(file, nr, line); |
| 51 | + |
| 52 | + if (errors > 0) |
| 53 | + stderr.writefln("%s error%s found. Exiting.", errors, errors > 1 ? "s" : ""); |
| 54 | + |
| 55 | + return errors != 0; |
| 56 | +} |
| 57 | + |
| 58 | +unittest |
| 59 | +{ |
| 60 | + string lastSeenError; |
| 61 | + void errorStub(string name, string file, size_t lineNr, const(char)[] line) |
| 62 | + { |
| 63 | + lastSeenError = name; |
| 64 | + } |
| 65 | + auto check(string line) |
| 66 | + { |
| 67 | + lastSeenError = null; |
| 68 | + checkLine!errorStub(null, 0, line); |
| 69 | + return lastSeenError; |
| 70 | + } |
| 71 | + |
| 72 | + assert(check(` <!--UNDEFINED MACRO: "D_CONTRIBUTORS"--> `) == ErrorMessages.undefinedMacro); |
| 73 | + |
| 74 | + assert(check(" $('") is null); |
| 75 | + assert(check(" $(") is null); |
| 76 | + assert(check(" $(FOO)") == ErrorMessages.rawMacroLeakage); |
| 77 | + |
| 78 | + assert(check(" )") is null); |
| 79 | + assert(check(") ") is null); |
| 80 | + assert(check(")") == ErrorMessages.trailingParenthesis); |
| 81 | +} |
0 commit comments