mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Derive inputs, output, and monomorphizations in build
This commit is contained in:
@@ -419,7 +419,7 @@ fn single_row_entries(parsed: &ParsedNodeFn, class: &Class, struct_name: &Ident,
|
||||
}
|
||||
}
|
||||
|
||||
fn implementation_rows(parsed: &ParsedNodeFn, regular_fields: &[&ParsedField]) -> Option<Vec<Vec<Type>>> {
|
||||
pub(crate) fn implementation_rows(parsed: &ParsedNodeFn, regular_fields: &[&ParsedField]) -> Option<Vec<Vec<Type>>> {
|
||||
let ctx_ident = context_param(parsed).map(|ctx| ctx.ident.clone());
|
||||
let open_generics: Vec<&Ident> = parsed
|
||||
.fn_generics
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
//! The intent IR: a node built from its signature, from which lowering derives.
|
||||
#![allow(dead_code)]
|
||||
|
||||
use crate::codegen::classify::{Dialect, context_param, dialect};
|
||||
use crate::parsing::ParsedNodeFn;
|
||||
use syn::{GenericParam, Ident, Type, TypeParamBound};
|
||||
use crate::codegen::classify::{
|
||||
Dialect, RoutingIo, bare_ident, context_param, dialect, flip_carrier, generic_assignment, generic_extractable, is_record_value, record_shape, routing_io, slot_value_type,
|
||||
};
|
||||
use crate::codegen::entries::implementation_rows;
|
||||
use crate::parsing::{AttributeRead, NodeParsedField, ParsedField, ParsedFieldType, ParsedNodeFn, RecordWrites, RegularParsedField, record_writes};
|
||||
use syn::{GenericArgument, GenericParam, Ident, PathArguments, Type, TypeParamBound};
|
||||
|
||||
pub(crate) fn build(parsed: &ParsedNodeFn) -> Node {
|
||||
let generics = generics(parsed);
|
||||
let generic_idents: Vec<Ident> = generics.iter().map(|generic| generic.ident.clone()).collect();
|
||||
let fields: Vec<&ParsedField> = parsed.fields.iter().filter(|field| !field.is_data_field).collect();
|
||||
Node {
|
||||
kernel: Kernel { fn_name: parsed.fn_name.clone() },
|
||||
generics: generics(parsed),
|
||||
monomorphizations: Vec::new(),
|
||||
inputs: Vec::new(),
|
||||
output: Output {
|
||||
shape: ItemShape {
|
||||
element: Element::Concrete(parsed.output_type.clone()),
|
||||
depth: 0,
|
||||
attrs: Vec::new(),
|
||||
},
|
||||
removes: Vec::new(),
|
||||
},
|
||||
monomorphizations: monomorphizations(parsed, &fields, &generic_idents),
|
||||
inputs: inputs(parsed, &fields, &generic_idents),
|
||||
output: output(parsed, &generic_idents),
|
||||
generics,
|
||||
effect: effect(parsed),
|
||||
}
|
||||
}
|
||||
@@ -38,6 +37,76 @@ fn generics(parsed: &ParsedNodeFn) -> Vec<Generic> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn inputs(parsed: &ParsedNodeFn, fields: &[&ParsedField], generics: &[Ident]) -> Vec<Input> {
|
||||
let routing = routing_io(parsed);
|
||||
let carrier_subject = flip_carrier(parsed) || record_shape(parsed).map_or(false, |shape| !shape.skips_carrier());
|
||||
fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, &field)| {
|
||||
let evaluation = match &field.ty {
|
||||
ParsedFieldType::Node(_) => Evaluation::Lazy,
|
||||
ParsedFieldType::Regular(_) => Evaluation::Eager,
|
||||
};
|
||||
Input {
|
||||
ident: field.pat_ident.ident.clone(),
|
||||
evaluation,
|
||||
shape: item_shape(field_element_type(field), &field.attribute_reads, generics),
|
||||
subject: subject(index, field, carrier_subject, routing.as_ref()),
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn subject(index: usize, field: &ParsedField, carrier_subject: bool, routing: Option<&RoutingIo>) -> bool {
|
||||
match &field.ty {
|
||||
ParsedFieldType::Node(NodeParsedField { output_type, .. }) => is_record_value(output_type) || routing.is_some_and(|routing| bare_ident(output_type) == Some(&routing.generic)),
|
||||
ParsedFieldType::Regular(RegularParsedField { ty, .. }) => routing.is_some_and(|routing| bare_ident(ty) == Some(&routing.generic)) || (index == 0 && carrier_subject),
|
||||
}
|
||||
}
|
||||
|
||||
fn output(parsed: &ParsedNodeFn, generics: &[Ident]) -> Output {
|
||||
let value = slot_value_type(&parsed.output_type);
|
||||
let (element, writes, removes) = match record_writes(&value) {
|
||||
Some(RecordWrites { element, markers, removes }) => (element, markers, removes),
|
||||
None => (value, Vec::new(), Vec::new()),
|
||||
};
|
||||
let (element, depth) = strip_ilist(&element);
|
||||
Output {
|
||||
shape: ItemShape {
|
||||
element: element_of(&element, generics),
|
||||
depth,
|
||||
attrs: writes.into_iter().map(|marker| LevelAttr { marker, level: 0 }).collect(),
|
||||
},
|
||||
removes: removes.into_iter().map(|marker| LevelAttr { marker, level: 0 }).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
fn monomorphizations(parsed: &ParsedNodeFn, fields: &[&ParsedField], generics: &[Ident]) -> Vec<ImplRow> {
|
||||
if generics.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
let Some(rows) = implementation_rows(parsed, fields) else {
|
||||
return Vec::new();
|
||||
};
|
||||
let positions: Option<Vec<(Ident, usize)>> = generics
|
||||
.iter()
|
||||
.map(|generic| fields.iter().position(|&field| generic_extractable(field_element_type(field), generic)).map(|index| (generic.clone(), index)))
|
||||
.collect();
|
||||
let Some(positions) = positions else {
|
||||
return Vec::new();
|
||||
};
|
||||
rows.iter()
|
||||
.filter_map(|row| {
|
||||
let assignments = positions
|
||||
.iter()
|
||||
.map(|(generic, index)| generic_assignment(field_element_type(fields[*index]), &row[*index], generic).map(|ty| (generic.clone(), ty)))
|
||||
.collect::<Option<Vec<_>>>()?;
|
||||
Some(ImplRow { assignments })
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn effect(parsed: &ParsedNodeFn) -> Effect {
|
||||
match dialect(parsed) {
|
||||
Dialect::Sync => Effect::Pure,
|
||||
@@ -47,6 +116,55 @@ fn effect(parsed: &ParsedNodeFn) -> Effect {
|
||||
}
|
||||
}
|
||||
|
||||
fn field_element_type(field: &ParsedField) -> &Type {
|
||||
match &field.ty {
|
||||
ParsedFieldType::Node(NodeParsedField { output_type, .. }) => output_type,
|
||||
ParsedFieldType::Regular(RegularParsedField { ty, .. }) => ty,
|
||||
}
|
||||
}
|
||||
|
||||
fn item_shape(element: &Type, reads: &[AttributeRead], generics: &[Ident]) -> ItemShape {
|
||||
let (element, depth) = strip_ilist(element);
|
||||
ItemShape {
|
||||
element: element_of(&element, generics),
|
||||
depth,
|
||||
attrs: reads.iter().map(|read| LevelAttr { marker: read.marker.clone(), level: 0 }).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
fn element_of(ty: &Type, generics: &[Ident]) -> Element {
|
||||
if is_record_value(ty) {
|
||||
return Element::Opaque;
|
||||
}
|
||||
match bare_ident(ty) {
|
||||
Some(ident) if generics.contains(ident) => Element::Generic(ident.clone()),
|
||||
_ => Element::Concrete(ty.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
fn strip_ilist(ty: &Type) -> (Type, u8) {
|
||||
let mut element = ty.clone();
|
||||
let mut depth = 0;
|
||||
while let Some(inner) = ilist_inner(&element) {
|
||||
element = inner;
|
||||
depth += 1;
|
||||
}
|
||||
(element, depth)
|
||||
}
|
||||
|
||||
fn ilist_inner(ty: &Type) -> Option<Type> {
|
||||
let Type::Path(path) = ty else { return None };
|
||||
let segment = path.path.segments.last()?;
|
||||
if segment.ident != "IList" {
|
||||
return None;
|
||||
}
|
||||
let PathArguments::AngleBracketed(args) = &segment.arguments else { return None };
|
||||
args.args.iter().find_map(|arg| match arg {
|
||||
GenericArgument::Type(inner) => Some(inner.clone()),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) struct Node {
|
||||
pub(crate) kernel: Kernel,
|
||||
pub(crate) generics: Vec<Generic>,
|
||||
@@ -75,7 +193,9 @@ pub(crate) struct ImplRow {
|
||||
pub(crate) struct Input {
|
||||
pub(crate) ident: Ident,
|
||||
pub(crate) evaluation: Evaluation,
|
||||
pub(crate) content: Content,
|
||||
pub(crate) shape: ItemShape,
|
||||
/// This input's layout folds into the output.
|
||||
pub(crate) subject: bool,
|
||||
}
|
||||
|
||||
/// `Lazy` = `impl Node<..>`, the kernel drives it.
|
||||
@@ -84,13 +204,6 @@ pub(crate) enum Evaluation {
|
||||
Lazy,
|
||||
}
|
||||
|
||||
pub(crate) enum Content {
|
||||
/// Configuration; not an item.
|
||||
Value(Type),
|
||||
/// `subject` = its layout (attrs + rank) flows to the output.
|
||||
Item { subject: bool, shape: ItemShape },
|
||||
}
|
||||
|
||||
pub(crate) struct Output {
|
||||
pub(crate) shape: ItemShape,
|
||||
pub(crate) removes: Vec<LevelAttr>,
|
||||
@@ -107,6 +220,8 @@ pub(crate) enum Element {
|
||||
Concrete(Type),
|
||||
/// Indexes [`Node::generics`].
|
||||
Generic(Ident),
|
||||
/// A whole erased record; the element type is unknown.
|
||||
Opaque,
|
||||
}
|
||||
|
||||
/// An attribute at a nesting level; `0` = innermost (the element's level).
|
||||
|
||||
Reference in New Issue
Block a user