Skip to content

Commit 2d80e5a

Browse files
committed
ci: Add slang linting
1 parent 808e7b3 commit 2d80e5a

File tree

4 files changed

+1060
-0
lines changed

4 files changed

+1060
-0
lines changed

.github/workflows/run_slang.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/usr/bin/env python3
2+
"""Run slang on a file list via pyslang's Driver API and emit a JSON diagnostic file."""
3+
4+
import sys
5+
import pyslang.driver as slang_driver
6+
7+
8+
def main():
9+
if len(sys.argv) != 3:
10+
print(f"Usage: {sys.argv[0]} <flist> <output.json>", file=sys.stderr)
11+
sys.exit(1)
12+
13+
flist, output_json = sys.argv[1], sys.argv[2]
14+
15+
driver = slang_driver.Driver()
16+
driver.parseCommandLine(
17+
f"-f {flist}"
18+
f" --top axi_lint_top"
19+
f" --error-limit 0"
20+
f" --diag-json {output_json}"
21+
)
22+
driver.runFullCompilation()
23+
# Exit 0 regardless of compile errors so the CI step continues
24+
# and reviewdog can annotate the diagnostics.
25+
26+
27+
if __name__ == "__main__":
28+
main()

.github/workflows/slang.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: Slang lint
2+
3+
on:
4+
push:
5+
pull_request:
6+
workflow_dispatch:
7+
8+
jobs:
9+
lint:
10+
runs-on: ubuntu-latest
11+
permissions:
12+
contents: read
13+
checks: write
14+
pull-requests: write
15+
16+
steps:
17+
- uses: actions/checkout@v4
18+
19+
- name: Install Bender
20+
uses: pulp-platform/pulp-actions/bender-install@v2.4.5
21+
22+
- name: Install pyslang
23+
run: pip install pyslang
24+
25+
- name: Generate file list
26+
run: bender script flist-plus -t lint > sources.flist
27+
28+
- name: Run slang
29+
run: python3 .github/workflows/run_slang.py sources.flist slang_diags.json
30+
31+
- name: Setup reviewdog
32+
uses: reviewdog/action-setup@v1
33+
with:
34+
reviewdog_version: latest
35+
36+
- name: Run reviewdog
37+
env:
38+
REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
39+
run: |
40+
python3 .github/workflows/slang_to_rdjson.py slang_diags.json \
41+
| reviewdog -f=rdjson \
42+
-name=slang \
43+
-reporter=${{ github.event_name == 'pull_request' && 'github-pr-review' || 'github-check' }} \
44+
-filter-mode=nofilter \
45+
-fail-level=error
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#!/usr/bin/env python3
2+
"""Convert slang JSON diagnostic output to reviewdog rdjson format."""
3+
4+
import json
5+
import re
6+
import sys
7+
8+
SEVERITY_MAP = {
9+
"error": "ERROR",
10+
"fatal": "ERROR",
11+
"warning": "WARNING",
12+
"note": "INFO",
13+
"info": "INFO",
14+
}
15+
16+
LOCATION_RE = re.compile(r'^(.+):(\d+):(\d+)$')
17+
18+
19+
def parse_location(location_str):
20+
"""Parse 'path:line:col' into a rdjson location object."""
21+
m = LOCATION_RE.match(location_str)
22+
if not m:
23+
return {"path": location_str}
24+
return {
25+
"path": m.group(1),
26+
"range": {
27+
"start": {
28+
"line": int(m.group(2)),
29+
"column": int(m.group(3)),
30+
}
31+
},
32+
}
33+
34+
35+
def convert(slang_diagnostics):
36+
diagnostics = []
37+
for d in slang_diagnostics:
38+
entry = {
39+
"message": d.get("message", ""),
40+
"location": parse_location(d.get("location", "")),
41+
"severity": SEVERITY_MAP.get(d.get("severity", "").lower(), "WARNING"),
42+
}
43+
option_name = d.get("optionName")
44+
if option_name:
45+
entry["code"] = {"value": option_name}
46+
if entry["severity"] == "WARNING":
47+
entry["code"]["url"] = "https://sv-lang.com/warning-ref.html#" + option_name
48+
diagnostics.append(entry)
49+
50+
return {
51+
"source": {
52+
"name": "slang",
53+
"url": "https://sv-lang.com",
54+
},
55+
"diagnostics": diagnostics,
56+
}
57+
58+
59+
def main():
60+
if len(sys.argv) != 2:
61+
print(f"Usage: {sys.argv[0]} <slang-output.json>", file=sys.stderr)
62+
sys.exit(1)
63+
with open(sys.argv[1]) as f:
64+
slang_diagnostics = json.load(f)
65+
result = convert(slang_diagnostics)
66+
json.dump(result, sys.stdout, indent=2)
67+
sys.stdout.write("\n")
68+
69+
70+
if __name__ == "__main__":
71+
main()

0 commit comments

Comments
 (0)