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
8 changes: 8 additions & 0 deletions rust/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 rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

[workspace]
resolver = "2"
members = ["crates/own-ir", "crates/own-syntax", "crates/own-cfg", "crates/own-diagnostics", "crates/own-analysis"]
members = ["crates/own-ir", "crates/own-syntax", "crates/own-cfg", "crates/own-diagnostics", "crates/own-analysis", "crates/own-lowered"]

[workspace.package]
edition = "2021"
Expand Down
7 changes: 7 additions & 0 deletions rust/crates/own-diagnostics/tests/dag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ fn allowed_edges() -> HashMap<&'static str, BTreeSet<&'static str>> {
m.insert("own-cfg", ["own-ir", "own-syntax"].into_iter().collect());
// The invariant #214 is about: only the span leaf, never the solver/parser.
m.insert("own-diagnostics", std::iter::once("own-ir").collect());
// The Layer 2 parity surface (#259): a DATA leaf like own-diagnostics —
// the typed model + canonical emitter of the normalized lowered
// representation. It deliberately depends on NO workspace crate: the
// future own-bridge will CONSTRUCT these types (own-bridge → own-lowered),
// never the reverse, and the surface must stay implementable without the
// lowering that fills it.
m.insert("own-lowered", BTreeSet::new());
// own-analysis CONSTRUCTS diagnostics and consumes the cfg lowering. It reads
// the effect type through `own_cfg::Effect`, NOT the parser — so there is no
// production own-syntax edge (own-syntax is a dev-only edge for its tests).
Expand Down
22 changes: 22 additions & 0 deletions rust/crates/own-lowered/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "own-lowered"
description = "Layer 2 normalized-lowered-representation surface: typed model + canonical emitter replaying the Python-authored goldens (tests/fixtures/lowered, LOWERED_VERSION 1) — the data half of the own-bridge parity contract (P-022 #259); no lowering, no MOS, no analysis wiring"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
publish.workspace = true
version = "0.1.0"

# A LEAF data crate, like own-diagnostics: it models the Layer 2 JSON surface
# (spec/Bridge.md §6, ownlang/lowered.py is the authoritative Python twin) and
# re-emits it byte-for-byte. It deliberately depends on NO other own-* crate —
# the future own-bridge will construct these types from real lowering; this
# crate must stay implementable without it (typed replay first, derivation
# later). serde_json is a REGULAR dependency: the canonical emitter is the
# crate's purpose, not a test aid.
[dependencies]
serde = { workspace = true }
serde_json = { workspace = true }

[lints]
workspace = true
27 changes: 27 additions & 0 deletions rust/crates/own-lowered/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//! The Layer 2 parity surface, typed (P-022 #259, spec/Bridge.md §6).
//!
//! `ownlang/lowered.py` is the authoritative Python emitter of the normalized
//! lowered representation; `tests/fixtures/lowered/` holds its frozen
//! facts/golden pairs under `manifest.json`. This crate is the **typed Rust
//! half of that contract**: a strict (`deny_unknown_fields`) data model of the
//! surface plus the canonical emitter that re-serializes it **byte-for-byte**
//! (2-space indent, fixed field order, raw UTF-8, trailing newline).
//!
//! Deliberately NOT here (next slices, gated separately): deriving these
//! documents from `OwnIR` facts (the lowering itself), `OwnIR` validation,
//! MOS inference, and any analysis wiring. A `rust_replay: false` manifest
//! case is a Python-only behavior snapshot pinning an open decision (#294)
//! and is not replayed by this crate's parity suite.
//!
//! Every shape here mirrors the frozen normalization decisions in the Python
//! emitter's docstring; a field added there without a matching change here (or
//! vice-versa) fails the replay suite, and `LOWERED_VERSION` must move in
//! lockstep on both sides.

mod model;

pub use model::{
parse_document, to_canonical_json, Extern, ExternParam, Function, HandleEntry, Lifetime,
LoweredDocument, Manifest, ManifestCase, Maybe, Param, Rejected, Resource, ResourceMember,
Stmt, Surface, TypeShape, LOWERED_VERSION,
};
Loading
Loading