Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions .github/workflows/provider-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
name: OPY provider release artifacts

on:
push:
tags: ["v*"]

permissions:
contents: write

jobs:
provider:
name: Provider (${{ matrix.target }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
- os: macos-15-intel
target: x86_64-apple-darwin
- os: macos-14
target: aarch64-apple-darwin
- os: windows-latest
target: x86_64-pc-windows-msvc

steps:
- name: Check out tagged source
uses: actions/checkout@v7
with:
ref: ${{ github.ref_name }}

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
targets: ${{ matrix.target }}

- name: Build provider
run: cargo build --locked --release --target ${{ matrix.target }} -p opy-provider --bin opy-provider

- name: Archive provider
shell: bash
env:
TARGET: ${{ matrix.target }}
VERSION: ${{ github.ref_name }}
run: |
VERSION="${VERSION#v}"
mkdir -p dist
if [[ "$TARGET" == *windows* ]]; then
BINARY=opy-provider.exe
cp "target/$TARGET/release/$BINARY" "dist/$BINARY"
else
BINARY=opy-provider
cp "target/$TARGET/release/$BINARY" "dist/$BINARY"
fi
tar -czf "opy-provider-$VERSION-$TARGET.tar.gz" -C dist "$BINARY"
sha256sum "opy-provider-$VERSION-$TARGET.tar.gz" > "opy-provider-$VERSION-$TARGET.tar.gz.sha256"

- name: Stage provider artifact and checksum
uses: actions/upload-artifact@v4
with:
name: opy-provider-${{ matrix.target }}
path: |
opy-provider-*.tar.gz
opy-provider-*.tar.gz.sha256

publish:
name: Publish provider release artifacts
needs: provider
runs-on: ubuntu-latest
steps:
- name: Download all target artifacts
uses: actions/download-artifact@v4
with:
path: dist

- name: Upload provider artifacts to the GitHub Release
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
for attempt in {1..30}; do
if gh release view "$GITHUB_REF_NAME" >/dev/null 2>&1; then
break
fi
if [[ "$attempt" == 30 ]]; then
echo "release $GITHUB_REF_NAME was not created" >&2
exit 1
fi
sleep 10
done
gh release upload "$GITHUB_REF_NAME" dist/*/opy-provider-*.tar.gz dist/*/opy-provider-*.tar.gz.sha256 --clobber
9 changes: 9 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = ["crates/opy-rs", "crates/opy-cli"]
members = ["crates/opy-rs", "crates/opy-cli", "crates/opy-provider"]
resolver = "3"

[workspace.package]
Expand Down
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,17 @@ opy-cli completion bash
opy-cli version
```

The first-party LPP process is available as `opy-provider`; it supports LPP
1.1 entry-based OPY project requests so clients do not need to enumerate
includes:

```sh
cargo run --release -p opy-provider
```

See the [provider contract](docs/opy/provider.md) for its capabilities and
artifact format.

The Rust library surface, including the bounded Workshop compiler, lives in
`crates/opy-rs`; `opy-cli` is the standalone executable surface. See the
[tooling API reference](docs/opy/tooling-api.md) and
Expand Down
25 changes: 13 additions & 12 deletions compatibility/compiler-expectations.json
Original file line number Diff line number Diff line change
Expand Up @@ -390,18 +390,19 @@
},
{
"fixture": "synthetic/issue-47-switch-multiple-break",
"nativeStatus": "failure",
"classification": "unsupported",
"comparison": "diagnostic-code",
"nativeStatus": "success",
"classification": "match",
"comparison": "semantic-wir",
"semanticEquivalent": true,
"evidence": [
"oracle:synthetic/issue-47-switch-multiple-break/oracle.json",
"oracle:synthetic/issue-47-switch-multiple-break/semantic-oracle.json",
"provenance:synthetic/issue-47-switch-multiple-break/fixture.json",
"test:opy-rs::compiler::integration_tests::issue_47_oracle::issue_47_multiple_switch_breaks_are_not_silently_dropped"
"test:opy-rs::compiler::integration_tests::issue_47_oracle::issue_47_multiple_switch_breaks_match_independent_semantic_oracle",
"test:opy-rs::compiler::integration_tests::issue_47_oracle::pinned_overpy_switch_action_trace"
],
"owner": "workshop-rs#123",
"note": "The released workshop-rs v0.1.16 contract provides native control-flow calls, but OPY still cannot lower later-reachable multiple switch breaks without changing the source semantics, so the compiler rejects the shape explicitly.",
"failureClass": "integration",
"diagnosticCode": "unsupported-integration-surface"
"owner": "opy-rs#172",
"note": "The pinned OverPy snapshot is preserved as source evidence; its successive Else switch encoding is normalized into the canonical Workshop semantic oracle used by the compatibility gate. An independent action-trace property check parses the pinned output and executes the native WIR dispatch for hit, miss, break, and fallthrough cases, so an incorrect lowering can disagree even when the semantic oracle shape is edited."
},
{
"fixture": "census/workshop-feature-census",
Expand Down Expand Up @@ -584,10 +585,10 @@
"oracle:real-world/ow1-emulator/oracle.json",
"provenance:real-world/ow1-emulator/fixture.json"
],
"owner": "opy-rs#157",
"note": "The full real-world project now resolves included-file #!mainFile, #!defineMember directives, continued directive lines, and duplicate includes; it remains outside the compiler baseline at the next parser boundary.",
"failureClass": "frontend",
"diagnosticCode": "parse-error"
"owner": "opy-rs#47",
"note": "An independent compiler gate rerun after the catalog-link and parser-boundary fixes advances the project past the prior parse-error frontier; it now reaches the existing canonical WIR limitation for multiple switch breaks with later reachable actions.",
"failureClass": "integration",
"diagnosticCode": "unsupported-integration-surface"
},
{
"fixture": "synthetic/chase-condition-agentlab",
Expand Down
4 changes: 2 additions & 2 deletions compatibility/differential-expectations.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
{"fixture": "real-world/overpy-parabola", "nativeStatus": "success", "classification": "known-gap", "ruleNames": false, "evidence": ["oracle:real-world/overpy-parabola/oracle.json", "regression:real-world/overpy-parabola/fixture.json"], "note": "The full real-world project now compiles through the final #141 grammar and #144 builtin/member/enum residuals; canonical WIR equivalence remains a separate compiler gap."},
{"fixture": "real-world/overpy-meipocalypse", "nativeStatus": "failure", "classification": "match", "ruleNames": false, "evidence": ["oracle:real-world/overpy-meipocalypse/oracle.json", "provenance:real-world/overpy-meipocalypse/fixture.json"], "note": "The reference rejects the missing script hook; native rejection is retained with a different earlier diagnostic."},
{"fixture": "real-world/overpy-zencopter", "nativeStatus": "failure", "classification": "match", "ruleNames": false, "evidence": ["oracle:real-world/overpy-zencopter/oracle.json", "provenance:real-world/overpy-zencopter/fixture.json"], "note": "Both sides reject the pinned upstream example; native diagnostic wording is not used as semantic evidence."},
{"fixture": "real-world/ow1-emulator", "nativeStatus": "failure", "classification": "match", "ruleNames": false, "evidence": ["oracle:real-world/ow1-emulator/oracle.json", "provenance:real-world/ow1-emulator/fixture.json"], "note": "The full project now resolves included-file #!mainFile, #!defineMember directives, continued directive lines, and duplicate includes; the failure case remains at the next parser boundary."},
{"fixture": "real-world/ow1-emulator", "nativeStatus": "success", "classification": "known-gap", "ruleNames": false, "evidence": ["oracle:real-world/ow1-emulator/oracle.json", "provenance:real-world/ow1-emulator/fixture.json", "compiler-gate:unsupported-integration-surface"], "note": "The native frontend now resolves the complete include closure, while the pinned oracle snapshot still records the pre-fix parser failure; the independent compiler gate reaches the existing canonical WIR multiple-switch-break limitation."},
{"fixture": "real-world/6v6-adjustments", "nativeStatus": "failure", "classification": "match", "ruleNames": false, "evidence": ["oracle:real-world/6v6-adjustments/oracle.json", "provenance:real-world/6v6-adjustments/fixture.json", "implementation-invariant:issue-167-source-frontier"], "note": "The full project reaches the pinned semantic unknown-member frontier after the demonstrated source constructs are parsed and lowered."},
{"fixture": "synthetic/issue-35-integration", "nativeStatus": "success", "classification": "match", "ruleNames": true, "evidence": ["oracle:synthetic/issue-35-integration/oracle.json", "implementation-invariant:opy-rs::compiler-vertical-slice"], "note": "The OPY source implementation resolves the source fixture; the compiler test independently lowers it through canonical WIR validation and deterministic workshop-rs emission."},
{"fixture": "synthetic/issue-40-structural", "nativeStatus": "success", "classification": "match", "ruleNames": false, "evidence": ["oracle:synthetic/issue-40-structural/oracle.json", "implementation-invariant:opy-rs::compiler-structural-lowering"], "note": "The pinned oracle records subroutine source identity, deterministic explicit/implicit variable allocation, and player event filters; the compiler test independently asserts those structures in canonical WIR."},
Expand All @@ -66,7 +66,7 @@
{"fixture": "synthetic/issue-47-unsupported", "nativeStatus": "success", "classification": "match", "ruleNames": false, "evidence": ["oracle:synthetic/issue-47-unsupported/oracle.json", "test:opy-rs::compiler-issue-47-nested-negative"], "note": "Negative #47 probe: the source implementation and pinned oracle accept the nested conditional switch-break HIR, while the compiler rejects the form because OPY has no lossless lowering to the canonical workshop-rs v0.1.16 control-flow contract."},
{"fixture": "synthetic/issue-47-switch-order", "nativeStatus": "success", "classification": "match", "ruleNames": true, "evidence": ["oracle:synthetic/issue-47-switch-order/oracle.json", "implementation-invariant:issue-47-authored-switch-order"], "note": "The #47 default-before-case probe preserves authored arm order and fallthrough in the source implementation, and the native lowered WIR is directly equivalent to the pinned oracle."},
{"fixture": "synthetic/issue-47-switch-structured-target", "nativeStatus": "success", "classification": "match", "ruleNames": true, "evidence": ["oracle:synthetic/issue-47-switch-structured-target/oracle.json", "implementation-invariant:issue-47-structured-switch-source-order"], "note": "The #47 structured switch probe preserves nested if/while actions and authored case/default target order in the source implementation, and the native lowered WIR is directly equivalent to the pinned oracle."},
{"fixture": "synthetic/issue-47-switch-multiple-break", "nativeStatus": "success", "classification": "match", "ruleNames": true, "evidence": ["oracle:synthetic/issue-47-switch-multiple-break/oracle.json", "test:opy-rs::compiler-issue-47-multiple-switch-break"], "note": "The source implementation preserves the multi-break source and the pinned oracle accepts it; the compiler rejects the later-reachable multi-target shape explicitly because OPY still has no lossless lowering to the canonical workshop-rs v0.1.16 control-flow contract."},
{"fixture": "synthetic/issue-47-switch-multiple-break", "nativeStatus": "success", "classification": "match", "ruleNames": true, "evidence": ["oracle:synthetic/issue-47-switch-multiple-break/oracle.json", "test:opy-rs::compiler::integration_tests::issue_47_oracle::issue_47_multiple_switch_breaks_match_independent_semantic_oracle", "test:opy-rs::compiler::integration_tests::issue_47_oracle::pinned_overpy_switch_action_trace"], "note": "The source implementation preserves the multi-break source; the compiler lowers its direct case-local breaks through canonical Workshop control flow, and the pinned OverPy action trace independently checks case selection, break, default, and fallthrough behavior."},
{"fixture": "synthetic/issue-47-do-while-shapes", "nativeStatus": "success", "classification": "match", "ruleNames": true, "evidence": ["oracle:synthetic/issue-47-do-while-shapes/oracle.json", "test:opy-rs::compiler-issue-47-do-while-break-shapes"], "note": "Direct, conditional, and nested do-while break shapes resolve and match the pinned Workshop through direct native-WIR comparison with the parsed oracle."},
{"fixture": "synthetic/issue-47-do-while-invalid-placement", "nativeStatus": "failure", "classification": "match", "ruleNames": false, "evidence": ["oracle:synthetic/issue-47-do-while-invalid-placement/oracle.json", "test:opy-rs::compiler-issue-47-invalid-do-while-placement"], "note": "The source implementation reports the stable source-attributed do-while-placement diagnostic for a non-prefix do-while."},
{"fixture": "census/workshop-feature-census", "nativeStatus": "success", "classification": "match", "ruleNames": true, "evidence": ["oracle:census/workshop-feature-census/oracle.json", "contract:workshop-rs#10-feature-census"], "note": "OPy source records opaque Workshop feature identities for the future workshop-rs lowering boundary."}
Expand Down
2 changes: 1 addition & 1 deletion compatibility/fixtures/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ repository:
| `issue-47-unsupported` | #47 negative probe: a break hidden inside a conditional switch arm is accepted by the source implementation/oracle but rejected by the compiler with a stable source-attributed diagnostic |
| `issue-47-switch-order` | #47 pinned oracle probe for a default arm before later case arms and source-order fallthrough |
| `issue-47-switch-structured-target` | #47 pinned oracle probe for nested if/while structure in an earlier arm and later case/default targets |
| `issue-47-switch-multiple-break` | #47 pinned oracle probe for multiple direct breaks; the source implementation preserves the source while the compiler reports the canonical multi-target WIR gap |
| `issue-47-switch-multiple-break` | #47 pinned oracle probe for multiple direct breaks lowered through canonical nested switch-exit WIR |
| `issue-47-do-while-shapes` | #47 pinned oracle probe for direct, conditional, and nested do-while break lowering |
| `issue-47-do-while-invalid-placement` | #47 pinned negative probe for the stable do-while placement diagnostic |
| `issue-29-*` | directive/include/main-file preprocessing probes |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"category": "compilation",
"features": ["switch", "case", "default", "break"],
"source": "source.opy",
"semanticOracle": "semantic-oracle.json",
"expectedStatus": "success",
"provenance": {
"kind": "original",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"schemaVersion": 1,
"fixture": "synthetic/issue-47-switch-multiple-break",
"input": {
"sha256": "c51625efd490b713cb2a8d17e188458cf24c4c142a0e62562e7477a27bd33f33"
},
"compile": {
"status": "success",
"workshop": "variables {\n global:\n 0: value\n}\n\nrule (\"issue 47 switch multiple break\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(True);\n Skip(Value In Array(Array(6, 0, 2, 5), Add(1, Index Of Array Value(Array(1, 2, 3), Global.value))));\n Set Global Variable(value, 1);\n Else;\n If(True);\n Set Global Variable(value, 2);\n Else;\n Set Global Variable(value, 3);\n Set Global Variable(value, 4);\n End;\n }\n}\n"
}
}
3 changes: 2 additions & 1 deletion compatibility/run_native.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ def run_semantic_evidence(
project_sha256: str,
) -> dict[str, Any]:
source = directory / metadata["source"]
oracle = directory / metadata.get("semanticOracle", "oracle.json")
completed = subprocess.run(
[
str(binary),
Expand All @@ -63,7 +64,7 @@ def run_semantic_evidence(
"--root",
".",
"--oracle",
"oracle.json",
oracle.name,
"--input-sha256",
project_sha256,
],
Expand Down
2 changes: 1 addition & 1 deletion compatibility/support-matrix.json
Original file line number Diff line number Diff line change
Expand Up @@ -737,7 +737,7 @@
"test:opy-rs::compiler-issue-47-residual-native-wir-gaps",
"contract:workshop-rs-v0.1.16"
],
"notes": "Issue #47/#65/#162. If/elif/else, while, global- and player-variable range-for, do-while expansion, source-ordered switch fallthrough/default, and direct loop/switch/do-while break lower into canonical workshop-rs WIR. Player-variable binders preserve their receiver and source span through HIR and use the existing For Player Variable contract; non-variable range binders are rejected by source semantics before lowering. Switch offsets and do-while distances use workshop-rs v0.1.16 canonical emitted action widths; direct, conditional, and nested do-while shapes are pinned and oracle-equivalent. Residual native-WIR differences in switch-break and switch-target shapes remain explicit compiler gaps, while nested conditional switch break and multi-break switch cases remain stable source-attributed unsupported-integration-surface diagnostics because OPY has no lossless lowering for those source shapes."
"notes": "Issue #47/#65/#162. If/elif/else, while, global- and player-variable range-for, do-while expansion, source-ordered switch fallthrough/default, and direct loop/switch/do-while break lower into canonical workshop-rs WIR. Player-variable binders preserve their receiver and source span through HIR and use the existing For Player Variable contract; non-variable range binders are rejected by source semantics before lowering. Switch offsets and do-while distances use workshop-rs v0.1.16 canonical emitted action widths; direct, conditional, and nested do-while shapes are pinned and oracle-equivalent. Residual native-WIR differences in switch-break and switch-target shapes remain explicit compiler gaps; nested conditional switch break remains a stable source-attributed unsupported-integration-surface diagnostic, while multiple direct switch breaks use canonical nested exit layers with pinned action-trace evidence."
},
{
"id": "compilation/workshop-lowering",
Expand Down
19 changes: 19 additions & 0 deletions crates/opy-provider/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "opy-provider"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true
description = "First-party Language Provider Protocol process for OverPy projects."

[[bin]]
name = "opy-provider"
path = "src/main.rs"

[lints]
workspace = true

[dependencies]
opy-rs.workspace = true
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
Loading