| 12 |
12 |
|
|
| 13 |
13 |
|
use proc_macro2::{Span, TokenStream};
|
| 14 |
14 |
|
use quote::{format_ident, quote};
|
| 15 |
|
- |
use syn::spanned::Spanned as _;
|
| 16 |
15 |
|
use syn::{LitStr, Result};
|
| 17 |
16 |
|
|
| 18 |
17 |
|
use crate::ast::{
|
| 111 |
110 |
|
/// signature as the shape it stands for, and a second spelling of this mapping
|
| 112 |
111 |
|
/// would drift from the first the moment a shaped type was added.
|
| 113 |
112 |
|
pub fn returns_type(returns: &syn::Type) -> Result<TokenStream> {
|
| 114 |
|
- |
let shaped = shaped_name(returns)?;
|
| 115 |
|
- |
Ok(match &shaped {
|
|
113 |
+ |
shaped_type(&shaped_name(returns)?)
|
|
114 |
+ |
}
|
|
115 |
+ |
|
|
116 |
+ |
/// The Rust type one [`Shaped`] is written as.
|
|
117 |
+ |
fn shaped_type(shaped: &Shaped) -> Result<TokenStream> {
|
|
118 |
+ |
Ok(match shaped {
|
| 116 |
119 |
|
Shaped::Nodes => quote!(::std::vec::Vec<::quasi_router::Node>),
|
| 117 |
120 |
|
Shaped::Acts => quote!(::std::vec::Vec<::quasi_router::Act>),
|
|
121 |
+ |
Shaped::Marked(inner) => {
|
|
122 |
+ |
let inner = shaped_type(inner)?;
|
|
123 |
+ |
quote!(::quasi_router::stage::Staged<#inner>)
|
|
124 |
+ |
}
|
| 118 |
125 |
|
Shaped::Single { name, optional } => {
|
| 119 |
|
- |
let shaped_type = format_ident!("{}", name, span = returns.span());
|
|
126 |
+ |
let shaped_type = format_ident!("{}", name, span = Span::call_site());
|
| 120 |
127 |
|
if *optional {
|
| 121 |
128 |
|
quote!(::std::option::Option<::quasi_router::#shaped_type>)
|
| 122 |
129 |
|
} else {
|
| 149 |
156 |
|
/// what a row offers and what a chosen set does. Every member is an `act`,
|
| 150 |
157 |
|
/// because a menu is nothing but controls.
|
| 151 |
158 |
|
Acts,
|
|
159 |
+ |
/// A staged twin's answer for either list: the value, and the marks beside
|
|
160 |
+ |
/// it.
|
|
161 |
+ |
///
|
|
162 |
+ |
/// A bare `Vec` has nowhere to keep a mark, so a twin answering one returns
|
|
163 |
+ |
/// `Staged<Vec<_>>` instead and whatever splices its members in absorbs
|
|
164 |
+ |
/// them at the offset they landed. A twin's return type is free -- nothing
|
|
165 |
+ |
/// but the derivation calls one -- which is what makes this available.
|
|
166 |
+ |
Marked(Box<Shaped>),
|
| 152 |
167 |
|
}
|
| 153 |
168 |
|
|
| 154 |
169 |
|
/// The type a shape returns, read off the declaration.
|
| 162 |
177 |
|
let Some(last) = path.path.segments.last() else {
|
| 163 |
178 |
|
return Err(syn::Error::new_spanned(returns, "an empty return type"));
|
| 164 |
179 |
|
};
|
|
180 |
+ |
if last.ident == "Staged" {
|
|
181 |
+ |
let Some(inner) = sole_argument(returns, &last.arguments)? else {
|
|
182 |
+ |
return Err(syn::Error::new_spanned(returns, "`Staged` of what?"));
|
|
183 |
+ |
};
|
|
184 |
+ |
return Ok(Shaped::Marked(Box::new(shaped_name(inner)?)));
|
|
185 |
+ |
}
|
| 165 |
186 |
|
if last.ident == "Vec" {
|
| 166 |
187 |
|
let Some(inner) = sole_argument(returns, &last.arguments)? else {
|
| 167 |
188 |
|
return Err(syn::Error::new_spanned(returns, "`Vec` of what?"));
|
| 206 |
227 |
|
returns,
|
| 207 |
228 |
|
"a menu with no entries is an empty `Vec<Act>`, not a `None`",
|
| 208 |
229 |
|
)),
|
|
230 |
+ |
Shaped::Marked(_) => Err(syn::Error::new_spanned(
|
|
231 |
+ |
returns,
|
|
232 |
+ |
"a twin's marks ride beside its value, so there is nothing for an \
|
|
233 |
+ |
`Option` to wrap here",
|
|
234 |
+ |
)),
|
| 209 |
235 |
|
};
|
| 210 |
236 |
|
}
|
| 211 |
237 |
|
Ok(Shaped::Single {
|
| 240 |
266 |
|
/// independent within one block.
|
| 241 |
267 |
|
fn value_body(items: &[Item], shaped: &Shaped, span: Span) -> Result<TokenStream> {
|
| 242 |
268 |
|
let shaped = match shaped {
|
| 243 |
|
- |
Shaped::Nodes => return nodes(items),
|
| 244 |
|
- |
Shaped::Acts => return acts(items),
|
|
269 |
+ |
Shaped::Nodes => return nodes(items, false),
|
|
270 |
+ |
Shaped::Acts => return acts(items, false),
|
|
271 |
+ |
Shaped::Marked(inner) => {
|
|
272 |
+ |
return match inner.as_ref() {
|
|
273 |
+ |
Shaped::Nodes => nodes(items, true),
|
|
274 |
+ |
Shaped::Acts => acts(items, true),
|
|
275 |
+ |
_ => Err(syn::Error::new(
|
|
276 |
+ |
span,
|
|
277 |
+ |
"only a list is answered with its marks beside it; every \
|
|
278 |
+ |
other container keeps its own",
|
|
279 |
+ |
)),
|
|
280 |
+ |
};
|
|
281 |
+ |
}
|
| 245 |
282 |
|
single @ Shaped::Single { .. } => single,
|
| 246 |
283 |
|
};
|
| 247 |
284 |
|
let Shaped::Single {
|
| 1885 |
1922 |
|
/// itself, and a `Vec` is told `push` and answers with nothing, so one of the
|
| 1886 |
1923 |
|
/// two spellings would have had to be special-cased inside the general form
|
| 1887 |
1924 |
|
/// anyway.
|
| 1888 |
|
- |
fn nodes(items: &[Item]) -> Result<TokenStream> {
|
|
1925 |
+ |
/// A panel's members, as a list.
|
|
1926 |
+ |
///
|
|
1927 |
+ |
/// `marked` is a staged twin, which answers `Staged<Vec<Node>>` instead: a bare
|
|
1928 |
+ |
/// `Vec` has nowhere to keep a mark, so the marks ride beside the value until
|
|
1929 |
+ |
/// whatever splices the members in absorbs them. Both forms accumulate into the
|
|
1930 |
+ |
/// same wrapper, so the marking block reads the same here as everywhere else,
|
|
1931 |
+ |
/// and the ordinary form takes the value back out at the end -- which costs a
|
|
1932 |
+ |
/// null pointer and no allocation.
|
|
1933 |
+ |
fn nodes(items: &[Item], marked: bool) -> Result<TokenStream> {
|
| 1889 |
1934 |
|
let held = format_ident!("nodes", span = Span::call_site());
|
| 1890 |
1935 |
|
let statements = node_statements(items, &held)?;
|
|
1936 |
+ |
let answer = if marked {
|
|
1937 |
+ |
quote!(#held)
|
|
1938 |
+ |
} else {
|
|
1939 |
+ |
quote!(#held.value)
|
|
1940 |
+ |
};
|
| 1891 |
1941 |
|
Ok(quote!({
|
| 1892 |
|
- |
let mut #held = ::std::vec::Vec::new();
|
|
1942 |
+ |
let mut #held =
|
|
1943 |
+ |
::quasi_router::stage::Staged::plain(::std::vec::Vec::new());
|
| 1893 |
1944 |
|
#(#statements)*
|
| 1894 |
|
- |
#held
|
|
1945 |
+ |
#answer
|
| 1895 |
1946 |
|
}))
|
| 1896 |
1947 |
|
}
|
| 1897 |
1948 |
|
|
| 1901 |
1952 |
|
/// nothing but controls. A guard and a loop work the way they do everywhere
|
| 1902 |
1953 |
|
/// else, which is the whole reason this exists -- audiofiles' row menu is
|
| 1903 |
1954 |
|
/// fourteen entries of which nine are conditional.
|
| 1904 |
|
- |
fn acts(items: &[Item]) -> Result<TokenStream> {
|
|
1955 |
+ |
/// A menu's entries, as a list. See [`nodes`] for what `marked` changes.
|
|
1956 |
+ |
fn acts(items: &[Item], marked: bool) -> Result<TokenStream> {
|
| 1905 |
1957 |
|
let held = format_ident!("entries", span = Span::call_site());
|
| 1906 |
1958 |
|
let statements = act_statements(items, &held)?;
|
|
1959 |
+ |
let answer = if marked {
|
|
1960 |
+ |
quote!(#held)
|
|
1961 |
+ |
} else {
|
|
1962 |
+ |
quote!(#held.value)
|
|
1963 |
+ |
};
|
| 1907 |
1964 |
|
Ok(quote!({
|
| 1908 |
|
- |
let mut #held = ::std::vec::Vec::new();
|
|
1965 |
+ |
let mut #held =
|
|
1966 |
+ |
::quasi_router::stage::Staged::plain(::std::vec::Vec::new());
|
| 1909 |
1967 |
|
#(#statements)*
|
| 1910 |
|
- |
#held
|
|
1968 |
+ |
#answer
|
| 1911 |
1969 |
|
}))
|
| 1912 |
1970 |
|
}
|
| 1913 |
1971 |
|
|
| 1915 |
1973 |
|
items
|
| 1916 |
1974 |
|
.iter()
|
| 1917 |
1975 |
|
.map(|item| match item {
|
| 1918 |
|
- |
// A bare `Vec` has nowhere to keep a mark. `Staged<Vec<_>>` is the
|
| 1919 |
|
- |
// wrapper that fixes it, and until this builder uses one, a shape
|
| 1920 |
|
- |
// whose members accrete into a list cannot be staged. Refused
|
| 1921 |
|
- |
// rather than dropped: a residual missing a branch the fill program
|
| 1922 |
|
- |
// has is a fault a request discovers.
|
| 1923 |
|
- |
Item::Marked { .. } => Err(syn::Error::new(
|
| 1924 |
|
- |
Span::call_site(),
|
| 1925 |
|
- |
"a menu's entries cannot be marked yet, so this shape cannot be staged",
|
| 1926 |
|
- |
)),
|
|
1976 |
+ |
// The wrapper is what a mark lives on: `Staged<Vec<_>>` is a
|
|
1977 |
+ |
// value and its marks beside it, which is the answer to a bare
|
|
1978 |
+ |
// `Vec` having nowhere to keep one.
|
|
1979 |
+ |
Item::Marked { site, varies, body } => {
|
|
1980 |
+ |
let inner = act_statements(body, entries)?;
|
|
1981 |
+ |
let varies = self::varies(varies)?;
|
|
1982 |
+ |
let plan = format_ident!("{}", crate::symbolic::PLAN, span = Span::call_site());
|
|
1983 |
+ |
let at = format_ident!("listed_from", span = Span::call_site());
|
|
1984 |
+ |
let to = format_ident!("listed_to", span = Span::call_site());
|
|
1985 |
+ |
Ok(quote!({
|
|
1986 |
+ |
let #at = ::quasi_router::stage::Marking::placed(&#entries);
|
|
1987 |
+ |
#(#inner)*
|
|
1988 |
+ |
let #to = ::quasi_router::stage::Marking::placed(&#entries);
|
|
1989 |
+ |
::quasi_router::stage::Marking::mark(
|
|
1990 |
+ |
&mut #entries,
|
|
1991 |
+ |
::quasi_router::stage::Mark {
|
|
1992 |
+ |
scope: #plan.scope(),
|
|
1993 |
+ |
id: #site,
|
|
1994 |
+ |
varies: #varies,
|
|
1995 |
+ |
from: #at,
|
|
1996 |
+ |
to: #to,
|
|
1997 |
+ |
},
|
|
1998 |
+ |
);
|
|
1999 |
+ |
}))
|
|
2000 |
+ |
}
|
| 1927 |
2001 |
|
Item::Bind { name, source } => {
|
| 1928 |
2002 |
|
let value = source_value(source)?;
|
| 1929 |
2003 |
|
Ok(quote!(let #name = #value;))
|
| 1948 |
2022 |
|
Ok(quote!({
|
| 1949 |
2023 |
|
let #held = #value;
|
| 1950 |
2024 |
|
if #test {
|
| 1951 |
|
- |
#entries.push(#held);
|
|
2025 |
+ |
#entries.value.push(#held);
|
| 1952 |
2026 |
|
}
|
| 1953 |
2027 |
|
}))
|
| 1954 |
2028 |
|
}
|
| 1955 |
2029 |
|
Item::Emit(emission) => {
|
| 1956 |
2030 |
|
let value = act(emission)?;
|
| 1957 |
|
- |
Ok(quote!(#entries.push(#value);))
|
|
2031 |
+ |
Ok(quote!(#entries.value.push(#value);))
|
| 1958 |
2032 |
|
}
|
| 1959 |
2033 |
|
Item::Attribute { name, .. } => Err(syn::Error::new(
|
| 1960 |
2034 |
|
name.span(),
|
| 1968 |
2042 |
|
items
|
| 1969 |
2043 |
|
.iter()
|
| 1970 |
2044 |
|
.map(|item| match item {
|
| 1971 |
|
- |
// A bare `Vec` has nowhere to keep a mark. `Staged<Vec<_>>` is the
|
| 1972 |
|
- |
// wrapper that fixes it, and until this builder uses one, a shape
|
| 1973 |
|
- |
// whose members accrete into a list cannot be staged. Refused
|
| 1974 |
|
- |
// rather than dropped: a residual missing a branch the fill program
|
| 1975 |
|
- |
// has is a fault a request discovers.
|
| 1976 |
|
- |
Item::Marked { .. } => Err(syn::Error::new(
|
| 1977 |
|
- |
Span::call_site(),
|
| 1978 |
|
- |
"a panel's members cannot be marked yet, so this shape cannot be staged",
|
| 1979 |
|
- |
)),
|
|
2045 |
+ |
// The wrapper is what a mark lives on: `Staged<Vec<_>>` is a
|
|
2046 |
+ |
// value and its marks beside it, which is the answer to a bare
|
|
2047 |
+ |
// `Vec` having nowhere to keep one.
|
|
2048 |
+ |
Item::Marked { site, varies, body } => {
|
|
2049 |
+ |
let inner = node_statements(body, nodes)?;
|
|
2050 |
+ |
let varies = self::varies(varies)?;
|
|
2051 |
+ |
let plan = format_ident!("{}", crate::symbolic::PLAN, span = Span::call_site());
|
|
2052 |
+ |
let at = format_ident!("listed_from", span = Span::call_site());
|
|
2053 |
+ |
let to = format_ident!("listed_to", span = Span::call_site());
|
|
2054 |
+ |
Ok(quote!({
|
|
2055 |
+ |
let #at = ::quasi_router::stage::Marking::placed(&#nodes);
|
|
2056 |
+ |
#(#inner)*
|
|
2057 |
+ |
let #to = ::quasi_router::stage::Marking::placed(&#nodes);
|
|
2058 |
+ |
::quasi_router::stage::Marking::mark(
|
|
2059 |
+ |
&mut #nodes,
|
|
2060 |
+ |
::quasi_router::stage::Mark {
|
|
2061 |
+ |
scope: #plan.scope(),
|
|
2062 |
+ |
id: #site,
|
|
2063 |
+ |
varies: #varies,
|
|
2064 |
+ |
from: #at,
|
|
2065 |
+ |
to: #to,
|
|
2066 |
+ |
},
|
|
2067 |
+ |
);
|
|
2068 |
+ |
}))
|
|
2069 |
+ |
}
|
| 1980 |
2070 |
|
Item::Bind { name, source } => {
|
| 1981 |
2071 |
|
let value = source_value(source)?;
|
| 1982 |
2072 |
|
Ok(quote!(let #name = #value;))
|
| 2001 |
2091 |
|
Ok(quote!({
|
| 2002 |
2092 |
|
let #member = #value;
|
| 2003 |
2093 |
|
if #test {
|
| 2004 |
|
- |
#nodes.push(#member);
|
|
2094 |
+ |
#nodes.value.push(#member);
|
| 2005 |
2095 |
|
}
|
| 2006 |
2096 |
|
}))
|
| 2007 |
2097 |
|
}
|
| 2008 |
2098 |
|
Item::Emit(emission) => {
|
| 2009 |
2099 |
|
let value = panel_member(emission)?;
|
| 2010 |
|
- |
Ok(quote!(#nodes.push(#value);))
|
|
2100 |
+ |
Ok(quote!(#nodes.value.push(#value);))
|
| 2011 |
2101 |
|
}
|
| 2012 |
2102 |
|
// The one attribute a panel takes, and it means in a panel what it
|
| 2013 |
2103 |
|
// means on a region: splice another shape's nodes in here. A panel
|
| 2021 |
2111 |
|
} if name == "extend" => {
|
| 2022 |
2112 |
|
refuse_body(name, body)?;
|
| 2023 |
2113 |
|
let spliced = args.iter().map(arg).collect::<Result<Vec<_>>>()?;
|
| 2024 |
|
- |
let extending = quote!(#(#nodes.extend(#spliced);)*);
|
|
2114 |
+ |
let extending = quote!(#(#nodes.value.extend(#spliced);)*);
|
| 2025 |
2115 |
|
guard.as_ref().map_or_else(
|
| 2026 |
2116 |
|
|| Ok(extending.clone()),
|
| 2027 |
2117 |
|
|guard| {
|
| 2093 |
2183 |
|
}
|
| 2094 |
2184 |
|
}
|
| 2095 |
2185 |
|
let statements = list_statements(&body, &rows)?;
|
|
2186 |
+ |
// The rows accrete into a wrapper so a marked run has somewhere to be
|
|
2187 |
+ |
// recorded, and the table absorbs those marks as it takes the rows. A list
|
|
2188 |
+ |
// declares no columns, so its members are numbered from the first row and
|
|
2189 |
+ |
// the offset is zero -- `Table::placed` counts the columns first and there
|
|
2190 |
+ |
// are none.
|
| 2096 |
2191 |
|
if more.is_empty() {
|
| 2097 |
2192 |
|
return Ok(quote!({
|
| 2098 |
|
- |
let mut #rows = ::std::vec::Vec::new();
|
|
2193 |
+ |
let mut #rows =
|
|
2194 |
+ |
::quasi_router::stage::Staged::plain(::std::vec::Vec::new());
|
| 2099 |
2195 |
|
#(#statements)*
|
| 2100 |
|
- |
::quasi_router::Node::list(#rows)
|
|
2196 |
+ |
let mut listed = ::quasi_router::Node::list(#rows.value);
|
|
2197 |
+ |
::quasi_router::stage::Marking::absorb(&mut listed, &#rows.marks, 0);
|
|
2198 |
+ |
listed
|
| 2101 |
2199 |
|
}));
|
| 2102 |
2200 |
|
}
|
| 2103 |
2201 |
|
Ok(quote!({
|
| 2104 |
|
- |
let mut #rows = ::std::vec::Vec::new();
|
|
2202 |
+ |
let mut #rows =
|
|
2203 |
+ |
::quasi_router::stage::Staged::plain(::std::vec::Vec::new());
|
| 2105 |
2204 |
|
#(#statements)*
|
| 2106 |
2205 |
|
let mut #rest = ::std::option::Option::None;
|
| 2107 |
2206 |
|
#(#more)*
|
| 2108 |
|
- |
::quasi_router::Node::Table {
|
|
2207 |
+ |
let mut listed = ::quasi_router::Node::Table {
|
| 2109 |
2208 |
|
columns: ::std::vec::Vec::new(),
|
| 2110 |
|
- |
rows: #rows,
|
|
2209 |
+ |
rows: #rows.value,
|
| 2111 |
2210 |
|
more: #rest,
|
| 2112 |
|
- |
}
|
|
2211 |
+ |
marks: ::quasi_router::stage::Marks::none(),
|
|
2212 |
+ |
};
|
|
2213 |
+ |
::quasi_router::stage::Marking::absorb(&mut listed, &#rows.marks, 0);
|
|
2214 |
+ |
listed
|
| 2113 |
2215 |
|
}))
|
| 2114 |
2216 |
|
}
|
| 2115 |
2217 |
|
|
| 2117 |
2219 |
|
items
|
| 2118 |
2220 |
|
.iter()
|
| 2119 |
2221 |
|
.map(|item| match item {
|
| 2120 |
|
- |
// A bare `Vec` has nowhere to keep a mark. `Staged<Vec<_>>` is the
|
| 2121 |
|
- |
// wrapper that fixes it, and until this builder uses one, a shape
|
| 2122 |
|
- |
// whose members accrete into a list cannot be staged. Refused
|
| 2123 |
|
- |
// rather than dropped: a residual missing a branch the fill program
|
| 2124 |
|
- |
// has is a fault a request discovers.
|
| 2125 |
|
- |
Item::Marked { .. } => Err(syn::Error::new(
|
| 2126 |
|
- |
Span::call_site(),
|
| 2127 |
|
- |
"a list's rows cannot be marked yet, so this shape cannot be staged",
|
| 2128 |
|
- |
)),
|
|
2222 |
+ |
// The wrapper is what a mark lives on: `Staged<Vec<_>>` is a
|
|
2223 |
+ |
// value and its marks beside it, which is the answer to a bare
|
|
2224 |
+ |
// `Vec` having nowhere to keep one.
|
|
2225 |
+ |
Item::Marked { site, varies, body } => {
|
|
2226 |
+ |
let inner = list_statements(&body.iter().collect::<Vec<_>>(), rows)?;
|
|
2227 |
+ |
let varies = self::varies(varies)?;
|
|
2228 |
+ |
let plan = format_ident!("{}", crate::symbolic::PLAN, span = Span::call_site());
|
|
2229 |
+ |
let at = format_ident!("listed_from", span = Span::call_site());
|
|
2230 |
+ |
let to = format_ident!("listed_to", span = Span::call_site());
|
|
2231 |
+ |
Ok(quote!({
|
|
2232 |
+ |
let #at = ::quasi_router::stage::Marking::placed(&#rows);
|
|
2233 |
+ |
#(#inner)*
|
|
2234 |
+ |
let #to = ::quasi_router::stage::Marking::placed(&#rows);
|
|
2235 |
+ |
::quasi_router::stage::Marking::mark(
|
|
2236 |
+ |
&mut #rows,
|
|
2237 |
+ |
::quasi_router::stage::Mark {
|
|
2238 |
+ |
scope: #plan.scope(),
|
|
2239 |
+ |
id: #site,
|
|
2240 |
+ |
varies: #varies,
|
|
2241 |
+ |
from: #at,
|
|
2242 |
+ |
to: #to,
|
|
2243 |
+ |
},
|
|
2244 |
+ |
);
|
|
2245 |
+ |
}))
|
|
2246 |
+ |
}
|
| 2129 |
2247 |
|
Item::Bind { name, source } => {
|
| 2130 |
2248 |
|
let value = source_value(source)?;
|
| 2131 |
2249 |
|
Ok(quote!(let #name = #value;))
|
| 2149 |
2267 |
|
Ok(quote!({
|
| 2150 |
2268 |
|
let #held = #value;
|
| 2151 |
2269 |
|
if #test {
|
| 2152 |
|
- |
#rows.push(#held);
|
|
2270 |
+ |
#rows.value.push(#held);
|
| 2153 |
2271 |
|
}
|
| 2154 |
2272 |
|
}))
|
| 2155 |
2273 |
|
}
|
| 2156 |
2274 |
|
Item::Emit(emission) => {
|
| 2157 |
2275 |
|
let row = list_row(emission)?;
|
| 2158 |
|
- |
Ok(quote!(#rows.push(#row);))
|
|
2276 |
+ |
Ok(quote!(#rows.value.push(#row);))
|
| 2159 |
2277 |
|
}
|
| 2160 |
2278 |
|
Item::Attribute { name, .. } => Err(syn::Error::new(
|
| 2161 |
2279 |
|
name.span(),
|