use super::{SsrError, SsrErrorKind, encode};
use crate::expr::{AccessError, AccessProvider, AccessSpelling, write_expression};
use crate::runtime::{Runtime, vocabulary};
use crate::write::{LinkSink, Writer};
use core::cell::Cell;
use vize_l0::id::NodeId;
use vize_l2::{op::InterpolationOp, resolution::Occurrence};
use vize_l3::decision::ssr::{NativeSelectedSetupSsrAnalysis, SsrSetupExpression};
pub fn emit_selected_setup_template<L: LinkSink>(
analysis: &NativeSelectedSetupSsrAnalysis<'_, '_, '_>,
) -> Result<Writer<L>, SsrError> {
encode(
analysis.artifact().source(),
analysis.ssr(),
None,
Some(analysis),
)
}
pub(super) fn write<L: LinkSink>(
writer: &mut Writer<L>,
analysis: &NativeSelectedSetupSsrAnalysis<'_, '_, '_>,
node: NodeId,
interpolation: &InterpolationOp<'_>,
) -> Result<(), SsrError> {
let fail = |kind| SsrError {
node: Some(node),
span: interpolation.span,
kind,
};
let row = analysis
.expression(node)
.ok_or_else(|| fail(SsrErrorKind::MissingAnalysis))?;
let resolution = row.resolution();
if !core::ptr::eq(resolution.file(), analysis.file()) || resolution.node() != node {
return Err(fail(SsrErrorKind::MissingAnalysis));
}
let table = resolution
.table()
.ok_or_else(|| fail(SsrErrorKind::MissingAnalysis))?;
if row.reads().len() != table.occurrences().len() {
return Err(fail(SsrErrorKind::MissingAnalysis));
}
let helper = vocabulary(Runtime::VueServerRenderer)
.helper("ssrInterpolate")
.ok_or_else(|| fail(SsrErrorKind::MissingRuntimeHelper))?;
writer.use_helper(helper);
writer.push("${_ssrInterpolate(");
write_expression(
writer,
analysis.artifact().source(),
table,
&SetupReads {
row,
index: Cell::new(0),
},
)
.map_err(|error| SsrError {
node: Some(node),
span: error.span,
kind: SsrErrorKind::Expression(error),
})?;
writer.push(")}");
Ok(())
}
struct SetupReads<'read, 'owner, 'arena> {
row: &'read SsrSetupExpression<'owner, 'arena>,
index: Cell<usize>,
}
impl AccessProvider for SetupReads<'_, '_, '_> {
fn spelling(&self, occurrence: &Occurrence<'_>) -> Result<AccessSpelling<'_>, AccessError> {
let index = self.index.get();
let read = self
.row
.reads()
.get(index)
.ok_or(AccessError::MissingBinding)?;
let binding = self
.row
.resolution()
.binding(occurrence.binding)
.ok_or(AccessError::MissingBinding)?;
if !core::ptr::eq(read.occurrence(), occurrence)
|| read.binding().id() != occurrence.binding
|| !read.binding().same_owner(binding)
{
return Err(AccessError::MissingBinding);
}
self.index.set(index + 1);
Ok(AccessSpelling::Rewrite {
prefix: "$setup.",
replacement: Some(read.occurrence().name),
suffix: "",
helper: None,
})
}
}