detree-vm 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. detree_vm-0.1.0/.clang-format +121 -0
  2. detree_vm-0.1.0/.github/release.yml +18 -0
  3. detree_vm-0.1.0/.github/workflows/deploy-docs.yml +55 -0
  4. detree_vm-0.1.0/.github/workflows/release.yml +207 -0
  5. detree_vm-0.1.0/.github/workflows/run-tests.yml +188 -0
  6. detree_vm-0.1.0/.github/workflows/semantic-pr-titles.yml +25 -0
  7. detree_vm-0.1.0/.gitignore +226 -0
  8. detree_vm-0.1.0/.pre-commit-config.yaml +71 -0
  9. detree_vm-0.1.0/AGENTS.md +136 -0
  10. detree_vm-0.1.0/CONTRIBUTING.md +80 -0
  11. detree_vm-0.1.0/LICENSE +21 -0
  12. detree_vm-0.1.0/PKG-INFO +75 -0
  13. detree_vm-0.1.0/README.md +45 -0
  14. detree_vm-0.1.0/docs/api/compiler.md +29 -0
  15. detree_vm-0.1.0/docs/api/facade.md +22 -0
  16. detree_vm-0.1.0/docs/api/index.md +14 -0
  17. detree_vm-0.1.0/docs/api/machine.md +41 -0
  18. detree_vm-0.1.0/docs/api/spec.md +22 -0
  19. detree_vm-0.1.0/docs/conf.py +83 -0
  20. detree_vm-0.1.0/docs/design/architecture.md +106 -0
  21. detree_vm-0.1.0/docs/guides/embedding.md +86 -0
  22. detree_vm-0.1.0/docs/index.md +87 -0
  23. detree_vm-0.1.0/docs/spec/README.md +79 -0
  24. detree_vm-0.1.0/docs/spec/c-api.md +196 -0
  25. detree_vm-0.1.0/docs/spec/conformance.md +137 -0
  26. detree_vm-0.1.0/docs/spec/ir.md +202 -0
  27. detree_vm-0.1.0/docs/spec/isa.md +318 -0
  28. detree_vm-0.1.0/docs/spec/machine.md +137 -0
  29. detree_vm-0.1.0/docs/spec/module.md +155 -0
  30. detree_vm-0.1.0/examples/c/driver.c +32 -0
  31. detree_vm-0.1.0/kernel/CMakeLists.txt +83 -0
  32. detree_vm-0.1.0/kernel/cpp/CMakeLists.txt +47 -0
  33. detree_vm-0.1.0/kernel/cpp/src/buffer.cpp +349 -0
  34. detree_vm-0.1.0/kernel/cpp/src/buffer.hpp +115 -0
  35. detree_vm-0.1.0/kernel/cpp/src/c_api.cpp +280 -0
  36. detree_vm-0.1.0/kernel/cpp/src/errors.hpp +81 -0
  37. detree_vm-0.1.0/kernel/cpp/src/isa.cpp +164 -0
  38. detree_vm-0.1.0/kernel/cpp/src/isa.hpp +306 -0
  39. detree_vm-0.1.0/kernel/cpp/src/machine.cpp +771 -0
  40. detree_vm-0.1.0/kernel/cpp/src/machine.hpp +170 -0
  41. detree_vm-0.1.0/kernel/cpp/src/module.cpp +646 -0
  42. detree_vm-0.1.0/kernel/cpp/src/module.hpp +98 -0
  43. detree_vm-0.1.0/kernel/cpp/tests/test_capi.c +134 -0
  44. detree_vm-0.1.0/kernel/include/detree.h +211 -0
  45. detree_vm-0.1.0/kernel/rust/CMakeLists.txt +35 -0
  46. detree_vm-0.1.0/kernel/rust/Cargo.toml +15 -0
  47. detree_vm-0.1.0/kernel/rust/src/buffer.rs +421 -0
  48. detree_vm-0.1.0/kernel/rust/src/capi.rs +483 -0
  49. detree_vm-0.1.0/kernel/rust/src/errors.rs +115 -0
  50. detree_vm-0.1.0/kernel/rust/src/isa.rs +548 -0
  51. detree_vm-0.1.0/kernel/rust/src/lib.rs +23 -0
  52. detree_vm-0.1.0/kernel/rust/src/machine.rs +1116 -0
  53. detree_vm-0.1.0/kernel/rust/src/module.rs +708 -0
  54. detree_vm-0.1.0/kernel/rust/tests/smoke.rs +122 -0
  55. detree_vm-0.1.0/pyproject.toml +101 -0
  56. detree_vm-0.1.0/spec/isa.toml +1095 -0
  57. detree_vm-0.1.0/spec/opt.toml +316 -0
  58. detree_vm-0.1.0/src/detree/__init__.py +66 -0
  59. detree_vm-0.1.0/src/detree/__main__.py +14 -0
  60. detree_vm-0.1.0/src/detree/_version.py +24 -0
  61. detree_vm-0.1.0/src/detree/abi/__init__.py +13 -0
  62. detree_vm-0.1.0/src/detree/abi/capi.py +552 -0
  63. detree_vm-0.1.0/src/detree/abi/libs.py +178 -0
  64. detree_vm-0.1.0/src/detree/backends/__init__.py +24 -0
  65. detree_vm-0.1.0/src/detree/backends/base.py +109 -0
  66. detree_vm-0.1.0/src/detree/backends/cpp.py +49 -0
  67. detree_vm-0.1.0/src/detree/backends/policy.py +29 -0
  68. detree_vm-0.1.0/src/detree/backends/python.py +47 -0
  69. detree_vm-0.1.0/src/detree/backends/registry.py +189 -0
  70. detree_vm-0.1.0/src/detree/backends/rust.py +48 -0
  71. detree_vm-0.1.0/src/detree/cli.py +205 -0
  72. detree_vm-0.1.0/src/detree/ir/__init__.py +27 -0
  73. detree_vm-0.1.0/src/detree/ir/builder.py +321 -0
  74. detree_vm-0.1.0/src/detree/ir/dump.py +240 -0
  75. detree_vm-0.1.0/src/detree/ir/errors.py +18 -0
  76. detree_vm-0.1.0/src/detree/ir/nodes.py +939 -0
  77. detree_vm-0.1.0/src/detree/ir/verify.py +647 -0
  78. detree_vm-0.1.0/src/detree/lower/__init__.py +207 -0
  79. detree_vm-0.1.0/src/detree/lower/codegen.py +81 -0
  80. detree_vm-0.1.0/src/detree/lower/linearize.py +692 -0
  81. detree_vm-0.1.0/src/detree/lower/regalloc.py +40 -0
  82. detree_vm-0.1.0/src/detree/machine.py +195 -0
  83. detree_vm-0.1.0/src/detree/opt/__init__.py +13 -0
  84. detree_vm-0.1.0/src/detree/opt/common.py +421 -0
  85. detree_vm-0.1.0/src/detree/opt/const.py +201 -0
  86. detree_vm-0.1.0/src/detree/opt/dead.py +182 -0
  87. detree_vm-0.1.0/src/detree/opt/fuse.py +985 -0
  88. detree_vm-0.1.0/src/detree/opt/inline.py +186 -0
  89. detree_vm-0.1.0/src/detree/opt/loops.py +88 -0
  90. detree_vm-0.1.0/src/detree/opt/manager.py +148 -0
  91. detree_vm-0.1.0/src/detree/opt/peephole.py +104 -0
  92. detree_vm-0.1.0/src/detree/py.typed +4 -0
  93. detree_vm-0.1.0/src/detree/spec/__init__.py +15 -0
  94. detree_vm-0.1.0/src/detree/spec/errors.py +129 -0
  95. detree_vm-0.1.0/src/detree/spec/isa.py +430 -0
  96. detree_vm-0.1.0/src/detree/spec/module.py +550 -0
  97. detree_vm-0.1.0/src/detree/spec/opinfo.py +116 -0
  98. detree_vm-0.1.0/src/detree/spec/validate.py +359 -0
  99. detree_vm-0.1.0/src/detree/vm/__init__.py +13 -0
  100. detree_vm-0.1.0/src/detree/vm/python.py +1076 -0
  101. detree_vm-0.1.0/tests/conftest.py +43 -0
  102. detree_vm-0.1.0/tests/corpus_cases.py +563 -0
  103. detree_vm-0.1.0/tests/data/README.md +12 -0
  104. detree_vm-0.1.0/tests/data/arithmetic.dtg +0 -0
  105. detree_vm-0.1.0/tests/data/assertion.dtg +0 -0
  106. detree_vm-0.1.0/tests/data/buffers_states_refs.dtg +0 -0
  107. detree_vm-0.1.0/tests/data/bulk.dtg +0 -0
  108. detree_vm-0.1.0/tests/data/bulk_until.dtg +0 -0
  109. detree_vm-0.1.0/tests/data/comparisons.dtg +0 -0
  110. detree_vm-0.1.0/tests/data/control.dtg +0 -0
  111. detree_vm-0.1.0/tests/data/cross_dtype.dtg +0 -0
  112. detree_vm-0.1.0/tests/data/fields.dtg +0 -0
  113. detree_vm-0.1.0/tests/data/fnbytes_array.dtg +0 -0
  114. detree_vm-0.1.0/tests/data/invalid_byte_count.dtg +0 -0
  115. detree_vm-0.1.0/tests/data/length_mismatch.dtg +0 -0
  116. detree_vm-0.1.0/tests/data/multi_event.dtg +0 -0
  117. detree_vm-0.1.0/tests/data/offsets.dtg +0 -0
  118. detree_vm-0.1.0/tests/data/scalars.dtg +0 -0
  119. detree_vm-0.1.0/tests/data/skips.dtg +0 -0
  120. detree_vm-0.1.0/tests/data/stack_overflow.dtg +0 -0
  121. detree_vm-0.1.0/tests/data/streams.dtg +0 -0
  122. detree_vm-0.1.0/tests/data/strings.dtg +0 -0
  123. detree_vm-0.1.0/tests/data/throw.dtg +0 -0
  124. detree_vm-0.1.0/tests/data/underflow.dtg +0 -0
  125. detree_vm-0.1.0/tests/data/variable_length_array.dtg +0 -0
  126. detree_vm-0.1.0/tests/module_builder.py +88 -0
  127. detree_vm-0.1.0/tests/test_abi_layout.py +97 -0
  128. detree_vm-0.1.0/tests/test_backends.py +67 -0
  129. detree_vm-0.1.0/tests/test_cli.py +83 -0
  130. detree_vm-0.1.0/tests/test_comment_style.py +58 -0
  131. detree_vm-0.1.0/tests/test_conformance.py +982 -0
  132. detree_vm-0.1.0/tests/test_cross_dtype.py +104 -0
  133. detree_vm-0.1.0/tests/test_differential.py +92 -0
  134. detree_vm-0.1.0/tests/test_docs.py +23 -0
  135. detree_vm-0.1.0/tests/test_errors.py +49 -0
  136. detree_vm-0.1.0/tests/test_fuzz_smoke.py +85 -0
  137. detree_vm-0.1.0/tests/test_golden.py +125 -0
  138. detree_vm-0.1.0/tests/test_golden_reduce.py +90 -0
  139. detree_vm-0.1.0/tests/test_imports.py +54 -0
  140. detree_vm-0.1.0/tests/test_inspect_wheel.py +16 -0
  141. detree_vm-0.1.0/tests/test_ir.py +172 -0
  142. detree_vm-0.1.0/tests/test_isa_tables.py +23 -0
  143. detree_vm-0.1.0/tests/test_lower.py +207 -0
  144. detree_vm-0.1.0/tests/test_machine.py +166 -0
  145. detree_vm-0.1.0/tests/test_opt.py +852 -0
  146. detree_vm-0.1.0/tests/test_validation.py +95 -0
  147. detree_vm-0.1.0/tests/test_vm.py +103 -0
  148. detree_vm-0.1.0/tools/abi_layout.c +36 -0
  149. detree_vm-0.1.0/tools/bench.py +302 -0
  150. detree_vm-0.1.0/tools/bench_capi.c +194 -0
  151. detree_vm-0.1.0/tools/check_docs.py +168 -0
  152. detree_vm-0.1.0/tools/gen_isa.py +389 -0
  153. detree_vm-0.1.0/tools/gen_opt.py +257 -0
  154. detree_vm-0.1.0/tools/golden.py +398 -0
  155. detree_vm-0.1.0/tools/inspect_wheel.py +113 -0
  156. detree_vm-0.1.0/tools/opt_report.py +174 -0
@@ -0,0 +1,121 @@
1
+ ---
2
+ # Derived from the Gaudi project's .clang-format; kept identical across the
3
+ # repositories that share this C++ style.
4
+ ---
5
+ Language: Cpp
6
+ BasedOnStyle: Google
7
+ AccessModifierOffset: -2
8
+ AlignAfterOpenBracket: Align
9
+ AlignConsecutiveAssignments: true
10
+ AlignConsecutiveDeclarations: false
11
+ AlignEscapedNewlines: Right
12
+ AlignOperands: true
13
+ AlignTrailingComments: true
14
+ AllowAllParametersOfDeclarationOnNextLine: true
15
+ AllowShortBlocksOnASingleLine: Always
16
+ AllowShortCaseLabelsOnASingleLine: true
17
+ AllowShortFunctionsOnASingleLine: All
18
+ AllowShortIfStatementsOnASingleLine: AllIfsAndElse
19
+ AllowShortLoopsOnASingleLine: true
20
+ AlwaysBreakAfterDefinitionReturnType: None
21
+ AlwaysBreakAfterReturnType: None
22
+ AlwaysBreakBeforeMultilineStrings: false
23
+ AlwaysBreakTemplateDeclarations: true
24
+ BinPackArguments: true
25
+ BinPackParameters: true
26
+ BraceWrapping:
27
+ AfterClass: false
28
+ AfterControlStatement: true
29
+ AfterEnum: false
30
+ AfterFunction: false
31
+ AfterNamespace: false
32
+ AfterObjCDeclaration: false
33
+ AfterStruct: false
34
+ AfterUnion: false
35
+ AfterExternBlock: false
36
+ BeforeCatch: false
37
+ BeforeElse: true
38
+ IndentBraces: false
39
+ SplitEmptyFunction: false
40
+ SplitEmptyRecord: false
41
+ SplitEmptyNamespace: false
42
+ BreakBeforeBinaryOperators: None
43
+ BreakBeforeBraces: Custom
44
+ BreakBeforeInheritanceComma: false
45
+ BreakBeforeTernaryOperators: true
46
+ BreakConstructorInitializersBeforeComma: true
47
+ BreakConstructorInitializers: BeforeComma
48
+ BreakAfterJavaFieldAnnotations: false
49
+ BreakStringLiterals: true
50
+ ColumnLimit: 95
51
+ CommentPragmas: '^ IWYU pragma:'
52
+ CompactNamespaces: false
53
+ ConstructorInitializerAllOnOneLineOrOnePerLine: true
54
+ ConstructorInitializerIndentWidth: 4
55
+ ContinuationIndentWidth: 4
56
+ Cpp11BracedListStyle: true
57
+ DerivePointerAlignment: false
58
+ DisableFormat: false
59
+ ExperimentalAutoDetectBinPacking: false
60
+ FixNamespaceComments: true
61
+ ForEachMacros:
62
+ - foreach
63
+ - Q_FOREACH
64
+ - BOOST_FOREACH
65
+ IncludeBlocks: Preserve
66
+ IncludeCategories:
67
+ - Regex: ^"(llvm|llvm-c|clang|clang-c)/
68
+ Priority: 2
69
+ - Regex: ^(<|"(gtest|gmock|isl|json)/)
70
+ Priority: 3
71
+ - Regex: .*
72
+ Priority: 1
73
+ IncludeIsMainRegex: (Test)?$
74
+ IndentCaseLabels: false
75
+ IndentPPDirectives: AfterHash
76
+ IndentWidth: 4
77
+ IndentWrappedFunctionNames: false
78
+ JavaScriptQuotes: Leave
79
+ JavaScriptWrapImports: true
80
+ KeepEmptyLinesAtTheStartOfBlocks: true
81
+ MacroBlockBegin: ''
82
+ MacroBlockEnd: ''
83
+ MaxEmptyLinesToKeep: 1
84
+ NamespaceIndentation: All
85
+ ObjCBinPackProtocolList: Auto
86
+ ObjCBlockIndentWidth: 2
87
+ ObjCSpaceAfterProperty: false
88
+ ObjCSpaceBeforeProtocolList: true
89
+ PenaltyBreakAssignment: 2
90
+ PenaltyBreakBeforeFirstCallParameter: 19
91
+ PenaltyBreakComment: 60
92
+ PenaltyBreakFirstLessLess: 30
93
+ PenaltyBreakString: 1000
94
+ PenaltyBreakTemplateDeclaration: 10
95
+ PenaltyExcessCharacter: 1000000
96
+ PenaltyReturnTypeOnItsOwnLine: 60
97
+ PointerAlignment: Left
98
+ ReflowComments: true
99
+ SortIncludes: CaseSensitive
100
+ SortUsingDeclarations: true
101
+ SpaceAfterCStyleCast: false
102
+ SpaceAfterTemplateKeyword: true
103
+ SpaceBeforeAssignmentOperators: true
104
+ SpaceBeforeCpp11BracedList: false
105
+ SpaceBeforeCtorInitializerColon: true
106
+ SpaceBeforeInheritanceColon: true
107
+ SpaceBeforeParens: ControlStatements
108
+ SpaceBeforeRangeBasedForLoopColon: true
109
+ SpaceInEmptyParentheses: false
110
+ SpacesBeforeTrailingComments: 1
111
+ SpacesInAngles: false
112
+ SpacesInContainerLiterals: true
113
+ SpacesInCStyleCastParentheses: false
114
+ SpacesInParentheses: true
115
+ Standard: c++11
116
+ TabWidth: 8
117
+ UseTab: Never
118
+ ---
119
+ Language: Json
120
+ IndentWidth: 4
121
+ ColumnLimit: 95
@@ -0,0 +1,18 @@
1
+ changelog:
2
+ categories:
3
+ - title: Breaking Changes
4
+ labels:
5
+ - breaking
6
+ - title: New Features
7
+ labels:
8
+ - feature
9
+ - title: Bug Fixes and Performance Improvements
10
+ labels:
11
+ - performance
12
+ - bug-fix
13
+ - title: Documentation
14
+ labels:
15
+ - documentation
16
+ - title: Other Changes
17
+ labels:
18
+ - '*'
@@ -0,0 +1,55 @@
1
+ name: deploy-docs
2
+
3
+ # Two entries: a manual deploy from any branch, and the release workflow, which
4
+ # calls this after PyPI so the published site always matches the tag. The site
5
+ # is the same `-W` build the `run-tests` docs job runs, so a broken page fails a
6
+ # pull request before it can fail a release.
7
+ on:
8
+ workflow_dispatch:
9
+ workflow_call:
10
+
11
+ permissions:
12
+ contents: read
13
+ pages: write
14
+ id-token: write
15
+
16
+ # A deploy in progress must not be cancelled: it would leave Pages serving a
17
+ # half-uploaded site.
18
+ concurrency:
19
+ group: pages
20
+ cancel-in-progress: false
21
+
22
+ jobs:
23
+ build:
24
+ name: build the site
25
+ runs-on: ubuntu-latest
26
+ steps:
27
+ - uses: actions/checkout@v6
28
+ - uses: astral-sh/setup-uv@v7
29
+ with:
30
+ python-version: '3.13'
31
+ activate-environment: true
32
+ enable-cache: true
33
+ # The documentation group carries Sphinx and the theme; the project itself
34
+ # is not installed because `docs/conf.py` imports from `src/`.
35
+ - name: Install the documentation toolchain
36
+ run: uv pip install --group docs
37
+ - name: Build the site
38
+ run: >-
39
+ .venv/bin/sphinx-build -b html -c docs -d build/docs/doctrees -W
40
+ docs build/docs/html
41
+ - uses: actions/configure-pages@v6
42
+ - uses: actions/upload-pages-artifact@v5
43
+ with:
44
+ path: build/docs/html
45
+
46
+ deploy:
47
+ name: deploy to GitHub Pages
48
+ needs: build
49
+ runs-on: ubuntu-latest
50
+ environment:
51
+ name: github-pages
52
+ url: ${{ steps.deployment.outputs.page_url }}
53
+ steps:
54
+ - id: deployment
55
+ uses: actions/deploy-pages@v5
@@ -0,0 +1,207 @@
1
+ name: Release
2
+
3
+ # A tag is the only trigger: the wheel version comes from setuptools_scm, and a
4
+ # release must be reproducible from the tagged commit (ADR 0009). A manual run
5
+ # would publish a branch build, so there is no `workflow_dispatch`.
6
+ on:
7
+ push:
8
+ tags: [v*]
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ env:
14
+ # The release build never sets DETREE_SHIP_BACKEND: the default is the Rust
15
+ # machine, and `both` would put the C++ library in the wheel, which
16
+ # tools/inspect_wheel.py rejects.
17
+ PYTHON_VERSION: '3.13'
18
+
19
+ jobs:
20
+ test:
21
+ # The whole test workflow, not a shortened copy: no wheel is built and
22
+ # nothing is published until the tagged commit passes what main passes.
23
+ uses: ./.github/workflows/run-tests.yml
24
+
25
+ wheels:
26
+ name: wheel (${{ matrix.name }})
27
+ needs: [test]
28
+ strategy:
29
+ fail-fast: false
30
+ matrix:
31
+ include:
32
+ - name: manylinux-x86_64
33
+ runner: ubuntu-24.04
34
+ image: quay.io/pypa/manylinux_2_28_x86_64
35
+ - name: manylinux-aarch64
36
+ runner: ubuntu-24.04-arm
37
+ image: quay.io/pypa/manylinux_2_28_aarch64
38
+ - name: macos-arm64
39
+ runner: macos-15
40
+ - name: windows-x64
41
+ runner: windows-2022
42
+ runs-on: ${{ matrix.runner }}
43
+ steps:
44
+ - uses: actions/checkout@v6
45
+
46
+ # The manylinux image is the only way to get a manylinux tag: a wheel
47
+ # built on the runner's glibc would repair to `linux_<arch>` and pip would
48
+ # never select it. `SETUPTOOLS_SCM_PRETEND_VERSION` removes the need for
49
+ # git inside the container.
50
+ - name: Build manylinux wheel
51
+ if: matrix.image
52
+ shell: bash
53
+ env:
54
+ SETUPTOOLS_SCM_PRETEND_VERSION: ${{ github.ref_name }}
55
+ run: |
56
+ set -euo pipefail
57
+ docker run --rm -v "$PWD:/work" -w /work \
58
+ -e SETUPTOOLS_SCM_PRETEND_VERSION \
59
+ "${{ matrix.image }}" bash -lc '
60
+ set -euo pipefail
61
+ curl -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain stable
62
+ . "$HOME/.cargo/env"
63
+ python=/opt/python/cp313-cp313/bin/python
64
+ "$python" -m pip install --quiet uv auditwheel
65
+ "$python" -m uv build --wheel --out-dir raw
66
+ "$python" -m auditwheel repair raw/*.whl -w dist
67
+ '
68
+
69
+ - uses: astral-sh/setup-uv@v7
70
+ if: ${{ !matrix.image }}
71
+ with:
72
+ python-version: ${{ env.PYTHON_VERSION }}
73
+
74
+ - uses: dtolnay/rust-toolchain@stable
75
+ if: ${{ !matrix.image }}
76
+
77
+ - name: Build native wheel
78
+ if: ${{ !matrix.image }}
79
+ shell: bash
80
+ env:
81
+ SETUPTOOLS_SCM_PRETEND_VERSION: ${{ github.ref_name }}
82
+ run: |
83
+ set -euo pipefail
84
+ uv build --wheel --out-dir dist
85
+
86
+ - uses: actions/upload-artifact@v7
87
+ with:
88
+ name: wheels-${{ matrix.name }}
89
+ path: dist/*.whl
90
+ if-no-files-found: error
91
+
92
+ sdist:
93
+ name: sdist
94
+ needs: [test]
95
+ runs-on: ubuntu-latest
96
+ steps:
97
+ - uses: actions/checkout@v6
98
+ with:
99
+ fetch-depth: 0
100
+ - uses: astral-sh/setup-uv@v7
101
+ with:
102
+ python-version: ${{ env.PYTHON_VERSION }}
103
+ - run: uv build --sdist --out-dir dist
104
+ - uses: actions/upload-artifact@v7
105
+ with:
106
+ name: sdist
107
+ path: dist/*.tar.gz
108
+ if-no-files-found: error
109
+
110
+ inspect:
111
+ name: inspect artifacts
112
+ needs: [wheels, sdist]
113
+ runs-on: ubuntu-latest
114
+ steps:
115
+ - uses: actions/checkout@v6
116
+ - uses: actions/download-artifact@v8
117
+ with:
118
+ path: dist
119
+ merge-multiple: true
120
+ - name: Check the wheel contract
121
+ run: python3 tools/inspect_wheel.py dist/*.whl
122
+ - name: Check the sdist carries the build sources
123
+ run: |
124
+ tar -tzf dist/*.tar.gz > sdist.txt
125
+ for path in kernel/cpp/CMakeLists.txt kernel/rust/src/lib.rs kernel/rust/Cargo.toml spec/isa.toml; do
126
+ grep -q "/$path$" sdist.txt || { echo "missing $path"; exit 1; }
127
+ done
128
+ - uses: actions/upload-artifact@v7
129
+ with:
130
+ name: dist
131
+ path: dist/*
132
+ if-no-files-found: error
133
+
134
+ smoke:
135
+ name: smoke (${{ matrix.runner }})
136
+ needs: [wheels]
137
+ strategy:
138
+ fail-fast: false
139
+ matrix:
140
+ runner: [ubuntu-latest, macos-15, windows-2022]
141
+ runs-on: ${{ matrix.runner }}
142
+ steps:
143
+ - uses: actions/checkout@v6
144
+ - uses: actions/download-artifact@v8
145
+ with:
146
+ path: dist
147
+ merge-multiple: true
148
+ - uses: astral-sh/setup-uv@v7
149
+ with:
150
+ python-version: ${{ env.PYTHON_VERSION }}
151
+ - name: Install and run the wheel
152
+ shell: bash
153
+ run: |
154
+ set -euo pipefail
155
+ uv venv /tmp/detree-release
156
+ if [ -f /tmp/detree-release/bin/python ]; then
157
+ python=/tmp/detree-release/bin/python
158
+ else
159
+ python=/tmp/detree-release/Scripts/python.exe
160
+ fi
161
+ # The local wheel is the only source for the new version; the index is
162
+ # allowed for numpy, which is a real dependency.
163
+ uv pip install --python "$python" --no-deps --find-links dist \
164
+ --prerelease=allow detree-vm
165
+ uv pip install --python "$python" numpy
166
+ "$python" -m detree backends
167
+ "$python" -c "import detree; assert detree.include_dir().joinpath('detree.h').is_file()"
168
+
169
+ pypi:
170
+ name: publish to PyPI
171
+ needs: [inspect, smoke]
172
+ runs-on: ubuntu-latest
173
+ environment:
174
+ name: pypi
175
+ url: https://pypi.org/project/detree-vm
176
+ permissions:
177
+ id-token: write
178
+ steps:
179
+ - uses: actions/download-artifact@v8
180
+ with:
181
+ name: dist
182
+ path: dist
183
+ - uses: pypa/gh-action-pypi-publish@release/v1
184
+
185
+ notes:
186
+ name: release notes
187
+ needs: [pypi]
188
+ runs-on: ubuntu-latest
189
+ permissions:
190
+ contents: write
191
+ steps:
192
+ - uses: actions/checkout@v6
193
+ - uses: softprops/action-gh-release@v2
194
+ with:
195
+ generate_release_notes: true
196
+
197
+ docs:
198
+ # After PyPI, so the published site describes a version that exists. The
199
+ # permissions are raised here because the caller's top-level `contents:
200
+ # read` would otherwise be all the called workflow could use.
201
+ name: deploy docs
202
+ needs: [pypi]
203
+ permissions:
204
+ contents: read
205
+ pages: write
206
+ id-token: write
207
+ uses: ./.github/workflows/deploy-docs.yml
@@ -0,0 +1,188 @@
1
+ name: run-tests
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+ # The release workflow calls this file so a tag is tested by exactly the CI
9
+ # that main runs, not by a second copy of the commands.
10
+ workflow_call:
11
+
12
+ concurrency:
13
+ group: ${{ github.workflow }}-${{ github.ref }}
14
+ cancel-in-progress: true
15
+
16
+ permissions:
17
+ contents: read
18
+
19
+ jobs:
20
+ python:
21
+ runs-on: ubuntu-latest
22
+ strategy:
23
+ fail-fast: false
24
+ matrix:
25
+ # The wheel is py3-none, so one compiled library serves every
26
+ # interpreter; the matrix runs the pure-Python and the compiled paths
27
+ # against every interpreter the metadata claims.
28
+ python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14']
29
+ steps:
30
+ - uses: actions/checkout@v6
31
+ - uses: astral-sh/setup-uv@v7
32
+ with:
33
+ python-version: ${{ matrix.python-version }}
34
+ activate-environment: true
35
+ enable-cache: true
36
+ - uses: dtolnay/rust-toolchain@stable
37
+ - name: Install
38
+ run: DETREE_SHIP_BACKEND=both uv pip install -e . --group dev
39
+ - name: Pre-commit
40
+ if: matrix.python-version == '3.13'
41
+ run: uv run pre-commit run --all-files
42
+ env:
43
+ SKIP: rustfmt
44
+ - name: Tests
45
+ run: uv run pytest -v
46
+
47
+ cpp:
48
+ runs-on: ubuntu-latest
49
+ steps:
50
+ - uses: actions/checkout@v6
51
+ - name: Configure
52
+ run: cmake -S kernel -B build/cpp -DDETREE_BUILD_TESTS=ON
53
+ - name: Build
54
+ run: cmake --build build/cpp -j4
55
+ - name: Test
56
+ run: ctest --test-dir build/cpp --output-on-failure
57
+
58
+ sanitizers:
59
+ # The C++ machine is the porting reference, so undefined behavior there is
60
+ # worth catching even though the release ships Rust.
61
+ runs-on: ubuntu-latest
62
+ steps:
63
+ - uses: actions/checkout@v6
64
+ - name: Configure
65
+ run: >
66
+ cmake -S kernel -B build/sanitize -DDETREE_BUILD_TESTS=ON
67
+ -DCMAKE_BUILD_TYPE=Debug
68
+ -DCMAKE_C_FLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer"
69
+ -DCMAKE_CXX_FLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer"
70
+ -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address,undefined"
71
+ -DCMAKE_SHARED_LINKER_FLAGS="-fsanitize=address,undefined"
72
+ - name: Build
73
+ run: cmake --build build/sanitize -j4
74
+ - name: Test
75
+ run: ctest --test-dir build/sanitize --output-on-failure
76
+ env:
77
+ ASAN_OPTIONS: detect_leaks=1:abort_on_error=1
78
+ UBSAN_OPTIONS: halt_on_error=1:print_stacktrace=1
79
+
80
+ rust:
81
+ runs-on: ubuntu-latest
82
+ steps:
83
+ - uses: actions/checkout@v6
84
+ - uses: dtolnay/rust-toolchain@stable
85
+ with:
86
+ components: rustfmt
87
+ - name: Format
88
+ run: cargo fmt --manifest-path kernel/rust/Cargo.toml --all -- --check
89
+ - name: Test
90
+ run: cargo test --manifest-path kernel/rust/Cargo.toml
91
+ - name: Build
92
+ run: cargo build --manifest-path kernel/rust/Cargo.toml --release
93
+
94
+ conformance:
95
+ # Three machines, one suite. The install builds both compiled libraries and
96
+ # the tests are run through the venv directly: `uv run` re-syncs the
97
+ # editable install to the Rust-only default, after which the `[cpp]` cases
98
+ # skip instead of fail and a green run proves nothing.
99
+ runs-on: ubuntu-latest
100
+ steps:
101
+ - uses: actions/checkout@v6
102
+ - uses: astral-sh/setup-uv@v7
103
+ with:
104
+ python-version: '3.13'
105
+ activate-environment: true
106
+ enable-cache: true
107
+ - uses: dtolnay/rust-toolchain@stable
108
+ - name: Install both machines
109
+ run: >-
110
+ DETREE_SHIP_BACKEND=both uv pip install -e . --group dev
111
+ --reinstall-package detree-vm
112
+ - name: Both libraries are installed
113
+ # A skipped backend is not a passing backend, so fail here rather than
114
+ # read a green suite that only ran the Python reference.
115
+ run: >-
116
+ .venv/bin/python -c "import sys; from detree.abi.libs import library_path;
117
+ missing = [n for n in ('cpp', 'rust') if library_path(n) is None];
118
+ sys.exit(f'missing compiled machine: {missing}' if missing else 0)"
119
+ - name: Backend identity
120
+ run: .venv/bin/python -m pytest -q tests/test_backends.py
121
+ - name: Python reference
122
+ run: DETREE_BACKEND=python .venv/bin/python -m pytest -q -rs
123
+ - name: C++ machine
124
+ run: DETREE_BACKEND=cpp .venv/bin/python -m pytest -q -rs
125
+ - name: Rust machine
126
+ run: DETREE_BACKEND=rust .venv/bin/python -m pytest -q -rs
127
+
128
+ docs:
129
+ runs-on: ubuntu-latest
130
+ steps:
131
+ - uses: actions/checkout@v6
132
+ - uses: astral-sh/setup-uv@v7
133
+ with:
134
+ python-version: '3.13'
135
+ activate-environment: true
136
+ enable-cache: true
137
+ - name: Install the documentation toolchain
138
+ run: uv pip install --group docs
139
+ - name: ISA tables
140
+ run: python3 tools/gen_isa.py --check
141
+ - name: Optimizer document
142
+ run: python3 tools/gen_opt.py --check
143
+ - name: Documentation
144
+ run: python3 tools/check_docs.py
145
+ - name: Golden corpus
146
+ run: python3 tools/golden.py --check
147
+ # The deploy workflow publishes this build, so a broken page has to fail
148
+ # the pull request instead of the release. `-W` is the same flag.
149
+ - name: Build the site
150
+ run: >-
151
+ .venv/bin/sphinx-build -b html -c docs -d build/docs/doctrees -W
152
+ docs build/docs/html
153
+
154
+ package:
155
+ # The release artifact is part of the product: build it on every change and
156
+ # check the wheel contract (one Rust library, the C header, a py3-none tag)
157
+ # before a tag ever exists.
158
+ #
159
+ # Skipped on a tag: `release.yml` builds the four artifacts it publishes and
160
+ # its `inspect` job runs the same contract checks, so a wheel built here
161
+ # would never be shipped and would only repeat the work.
162
+ if: github.ref_type != 'tag'
163
+ runs-on: ubuntu-latest
164
+ steps:
165
+ - uses: actions/checkout@v6
166
+ - uses: astral-sh/setup-uv@v7
167
+ with:
168
+ python-version: '3.13'
169
+ - uses: dtolnay/rust-toolchain@stable
170
+ - name: Build
171
+ run: |
172
+ uv build --wheel --out-dir dist
173
+ uv build --sdist --out-dir dist
174
+ - name: Wheel contract
175
+ run: python3 tools/inspect_wheel.py dist/*.whl
176
+ - name: Sdist carries the build sources
177
+ run: |
178
+ tar -tzf dist/*.tar.gz > sdist.txt
179
+ for path in kernel/cpp/CMakeLists.txt kernel/rust/src/lib.rs kernel/rust/Cargo.toml spec/isa.toml; do
180
+ grep -q "/$path$" sdist.txt || { echo "missing $path"; exit 1; }
181
+ done
182
+ - name: Install the wheel in a clean environment
183
+ run: |
184
+ uv venv /tmp/detree-wheel
185
+ uv pip install --python /tmp/detree-wheel/bin/python --no-deps \
186
+ --find-links dist --prerelease=allow detree-vm
187
+ uv pip install --python /tmp/detree-wheel/bin/python numpy
188
+ /tmp/detree-wheel/bin/python -m detree backends
@@ -0,0 +1,25 @@
1
+ name: Lint PR
2
+
3
+ # `pull_request`, not `pull_request_target`: from 2026-12-02 GitHub blocks the
4
+ # target trigger by default in public repositories, and this check only reads
5
+ # the event payload, so it needs neither the base checkout nor a secret.
6
+ on:
7
+ pull_request:
8
+ types:
9
+ - opened
10
+ - edited
11
+ - reopened
12
+
13
+ permissions:
14
+ pull-requests: read
15
+
16
+ jobs:
17
+ title:
18
+ name: Validate PR title
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ # The title becomes the squash commit subject, so it is held to the same
22
+ # Conventional Commits rule as a hand-written commit (CONTRIBUTING.md).
23
+ - uses: amannn/action-semantic-pull-request@v6
24
+ env:
25
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}