use std::sync::Arc;
use pedant_core::resolution::go::{GoProjectResolution, GoResolutionSnapshot};
use pedant_types::{ResolutionRecord, ResolutionReport, SymbolDefinition, SymbolReference};
use crate::error::GraphBuildError;
use crate::graph::CodeGraph;
use crate::limits::GraphLimits;
use crate::node::GraphNodeKind;
use crate::projection::assembly;
use crate::projection::draft::{PlacedFragment, ProjectionPlan, SourceFragment};
use crate::projection::placement::{
DefinitionTable, PlacedSource, RecordPlacement, SourceRecords, SourceSet,
};
use crate::projection::state::ProjectionCapacity;
use crate::projection::validation as neutral;
use super::mapping::{self, Vocabulary};
use super::placement::{self, PlannedUnits};
use super::validation;
struct Inputs<'a> {
report: &'a ResolutionReport,
vocabulary: Vocabulary,
resolved: Box<[(&'a SymbolReference, &'a ResolutionRecord)]>,
}
struct StatedSource<'a> {
table: &'a DefinitionTable,
vocabulary: &'a Vocabulary,
report: &'a ResolutionReport,
placed: &'a PlacedSource,
records: &'a SourceRecords<'a>,
}
pub(crate) fn project(
snapshot: &GoResolutionSnapshot,
resolution: &GoProjectResolution,
limits: GraphLimits,
) -> Result<CodeGraph, GraphBuildError> {
validation::check_snapshot_identity(snapshot, resolution)?;
let planned = plan(snapshot, resolution)?;
assembly::assemble(&planned, limits)
}
fn plan(
snapshot: &GoResolutionSnapshot,
resolution: &GoProjectResolution,
) -> Result<ProjectionPlan, GraphBuildError> {
let report = resolution.report();
let inputs = Inputs {
report,
vocabulary: Vocabulary::new(),
resolved: neutral::resolved_references(report)?,
};
let planned: PlannedUnits = placement::plan_units(snapshot, resolution, &inputs.vocabulary)?;
let capacity = ProjectionCapacity::stated(
planned.units.len(),
report,
&inputs.resolved,
snapshot.edges().len(),
);
let sources = SourceSet::new(planned.units)?;
let table = DefinitionTable::new(report, &sources)?;
let records = RecordPlacement::stated(report, &inputs.resolved, (&sources, &table))?;
let fragments = plan_fragments(&inputs, (&sources, &table, &records))?;
let dependencies = placement::plan_dependencies(snapshot, &planned.modules)?;
Ok(ProjectionPlan {
tier: report.tier(),
units: sources.finish(),
declarations: planned.declarations,
fragments,
definitions: records.definitions,
references: records.references,
dependencies,
capacity,
})
}
fn plan_fragments<'a>(
inputs: &Inputs<'a>,
placed: (&SourceSet, &DefinitionTable, &RecordPlacement<'a>),
) -> Result<Box<[PlacedFragment]>, GraphBuildError> {
let (sources, table, records) = placed;
sources
.placed()
.iter()
.zip(records.stated.iter())
.map(|(placed, stated)| {
let source = StatedSource {
table,
vocabulary: &inputs.vocabulary,
report: inputs.report,
placed,
records: stated,
};
Ok(PlacedFragment {
unit: placed.unit,
fragment: Arc::new(derived_fragment(&source)?),
})
})
.collect()
}
fn derived_fragment(stated: &StatedSource<'_>) -> Result<SourceFragment, GraphBuildError> {
SourceFragment::derived(
(stated.placed, stated.table),
stated.records,
(
|definition: &SymbolDefinition| definition_kind(stated, definition),
mapping::reference_kind,
),
)
}
fn definition_kind(
stated: &StatedSource<'_>,
definition: &SymbolDefinition,
) -> Result<GraphNodeKind, GraphBuildError> {
let holder = placement::holder_kind(stated.report, definition)?;
neutral::stated_definition_kind(
stated.vocabulary.definition(definition.kind(), holder),
definition,
)
}