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
2 changes: 1 addition & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,7 @@ Cleared (prior PR #521): `DerivedOpEffect { method, path_template, shape }` coll

### Lane 1 Stage 1e

**In progress on the current branch (pending merge):** `src/v3/compiler/src/emit.rs` now exists as the shared emit entrypoint with `EmitTarget`, `EmitMode`, `EmittedSource`, `emit(...)`, and `emit_module(...)`. The first migrated target is **Go**: its hand-written renderer moved under `emit.rs`, and `src/v3/compiler/src/emit_go.rs` is reduced to a compatibility adapter that forwards into the shared path. Coverage is locked by `m1_3_emit_go_test` plus `emit::tests::*`, including a wrapper-parity test proving `emit_go` / `emit_go_module` are thin adapters over the shared entrypoint. The authoritative scaffold receipt now lives in `docs/phase1-lane3-consolidation-build-plan.md` §"Wrapper exception receipt": Go's adapter is allowed only because its body already moved under `emit.rs`; Rust/Python do not get wrapper copies in advance, and all wrappers delete at Stage 1e.6. Rust and Python remain on legacy drivers; full recursive walker unification is still the remaining Stage 1e work.
**In progress on the current branch (pending merge):** `src/v3/compiler/src/emit.rs` now exists as the shared emit entrypoint with `EmitTarget`, `EmitMode`, `EmittedSource`, `emit(...)`, and `emit_module(...)`. The first migrated target is **Go**: its hand-written renderer moved under `emit.rs`, and `src/v3/compiler/src/emit_go.rs` is reduced to a compatibility adapter that forwards into the shared path. Coverage is locked by `m1_3_emit_go_test` plus `emit::tests::*`, including a wrapper-parity test proving `emit_go` / `emit_go_module` are thin adapters over the shared entrypoint. The authoritative scaffold receipt now lives in `docs/phase1-lane3-consolidation-build-plan.md` §"Wrapper exception receipt": Go's adapter is allowed only because its body already moved under `emit.rs`; Rust/Python do not get wrapper copies in advance, and all wrappers delete at Stage 1e.6. Follow-up namespace unification moved the remaining per-target monoliths under `src/v3/compiler/src/emit/*_target.rs`, with `emit.rs` staying the single dispatch surface and the old `emit_<target>.rs` files reduced to compatibility adapters only after their bodies moved in the same diff. Rust and Python remain target-monolithic under that shared namespace; full recursive walker unification is still the remaining Stage 1e work.

### Cross-cutting — performance

Expand Down
56 changes: 48 additions & 8 deletions src/v3/compiler/src/emit.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
//! Shared emit entrypoint and Stage 1e scaffolding.
//!
//! `emit.rs` is the single dispatch surface for all targets. Each
//! `*_target.rs` sibling still contains one target-monolithic
//! implementation body; the behavior-by-behavior lifts planned in α
//! §10 Stages 1e.2–1e.4 will move logic out of those files into
//! generic walker helpers here. Until that dissolution lands,
//! target-private carriers stay inside their target module and no
//! cross-target code should read them.

pub(crate) mod python_target;
pub(crate) mod rust_target;

use std::collections::{HashMap, HashSet};

use self::python_target::EmitPythonError;
use self::rust_target::{EmitError, RealizationCategory, SubstrateMarkerRole};
use crate::dag::{
ArrowBody, AtomPayload, Behavior, BranchNode, BranchPattern, CardinalityBound, DeclarationId,
Field, FieldValue, LiteralBits, Path, PortId, TemplateArgument, TransformNode, TransformTarget,
TypeConnective, ValueBody,
};
use crate::emit_rust::{EmitError, RealizationCategory};
use crate::operators::OperatorKind;
use crate::variant_payload::{
variant_payload_shape, VariantPayloadBinding, VariantPayloadFieldAccessRuleBinding,
Expand Down Expand Up @@ -620,6 +634,8 @@ impl TargetExecutionModelBinding {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EmitTarget {
Go,
Rust,
Python,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
Expand All @@ -635,21 +651,45 @@ pub struct EmittedSource {
pub mode: EmitMode,
}

pub fn emit(dag: &Dag, target: EmitTarget) -> Result<EmittedSource, EmitError> {
#[derive(Debug, Clone)]
pub enum EmitDispatchError {
Core(EmitError),
Python(EmitPythonError),
}

impl From<EmitError> for EmitDispatchError {
fn from(value: EmitError) -> Self {
Self::Core(value)
}
}

impl From<EmitPythonError> for EmitDispatchError {
fn from(value: EmitPythonError) -> Self {
Self::Python(value)
}
}

pub fn emit(dag: &Dag, target: EmitTarget) -> Result<EmittedSource, EmitDispatchError> {
emit_with_mode(dag, target, EmitMode::Program)
}

pub fn emit_module(dag: &Dag, target: EmitTarget) -> Result<EmittedSource, EmitError> {
pub fn emit_module(dag: &Dag, target: EmitTarget) -> Result<EmittedSource, EmitDispatchError> {
emit_with_mode(dag, target, EmitMode::Module)
}

fn emit_with_mode(
dag: &Dag,
target: EmitTarget,
mode: EmitMode,
) -> Result<EmittedSource, EmitError> {
) -> Result<EmittedSource, EmitDispatchError> {
let text = match target {
EmitTarget::Go => emit_go_with_mode(dag, mode)?,
EmitTarget::Go => emit_go_with_mode(dag, mode).map_err(EmitDispatchError::Core)?,
EmitTarget::Rust => {
rust_target::emit_rust_with_mode(dag, mode).map_err(EmitDispatchError::Core)?
}
EmitTarget::Python => {
python_target::emit_python_with_mode(dag, mode).map_err(EmitDispatchError::Python)?
}
};
Ok(EmittedSource { text, target, mode })
}
Expand All @@ -661,9 +701,9 @@ fn emit_go_with_mode(dag: &Dag, mode: EmitMode) -> Result<String, EmitError> {
"emit_go requires a non-ownership execution model".to_string(),
));
}
let main_marker = dag.main_marker().ok_or(EmitError::MissingSubstrateMarker(
crate::emit_rust::SubstrateMarkerRole::Main,
))?;
let main_marker = dag
.main_marker()
.ok_or(EmitError::MissingSubstrateMarker(SubstrateMarkerRole::Main))?;
let type_decls: Vec<_> = dag
.declarations()
.iter()
Expand Down
Loading
Loading