| 30 |
30 |
|
Run,
|
| 31 |
31 |
|
/// One control: its body sets, and emits nothing.
|
| 32 |
32 |
|
Act,
|
|
33 |
+ |
/// One field: its body sets, and emits nothing.
|
|
34 |
+ |
Field,
|
| 33 |
35 |
|
/// A document: its members are regions, held as slots rather than nodes.
|
| 34 |
36 |
|
Screen,
|
| 35 |
37 |
|
/// One row of a list: its members are the controls it offers.
|
| 199 |
201 |
|
));
|
| 200 |
202 |
|
}
|
| 201 |
203 |
|
},
|
|
204 |
+ |
"Slot" => match only {
|
|
205 |
+ |
Emission::Region { name, kind, body } => slot(name, kind, body)?,
|
|
206 |
+ |
other => {
|
|
207 |
+ |
return Err(syn::Error::new(
|
|
208 |
+ |
emission_span(other),
|
|
209 |
+ |
"a `-> Slot` shape is its single `region` member",
|
|
210 |
+ |
));
|
|
211 |
+ |
}
|
|
212 |
+ |
},
|
| 202 |
213 |
|
"Row" => match only {
|
| 203 |
214 |
|
Emission::Row { primary, body } => row(primary, body)?,
|
| 204 |
215 |
|
other => {
|
| 311 |
322 |
|
quote!(#built = #built #call;)
|
| 312 |
323 |
|
}
|
| 313 |
324 |
|
Item::For {
|
|
325 |
+ |
dereferenced,
|
| 314 |
326 |
|
binder,
|
| 315 |
327 |
|
iterable,
|
| 316 |
328 |
|
body,
|
| 317 |
329 |
|
} => {
|
| 318 |
330 |
|
let iterable = hole(iterable)?;
|
| 319 |
331 |
|
let inner = self::statements(body, container, built)?;
|
|
332 |
+ |
let binder = binder_pattern(*dereferenced, binder);
|
| 320 |
333 |
|
quote!(for #binder in #iterable { #(#inner)* })
|
| 321 |
334 |
|
}
|
| 322 |
335 |
|
Item::Emit(Emission::Guarded { guard, inner }) => {
|
| 419 |
432 |
|
emission_span(other),
|
| 420 |
433 |
|
"a row ranks what it holds: write `beside <priority> <emission>`",
|
| 421 |
434 |
|
)),
|
| 422 |
|
- |
(Container::Act, other) => Err(syn::Error::new(
|
|
435 |
+ |
(Container::Act | Container::Field, other) => Err(syn::Error::new(
|
| 423 |
436 |
|
emission_span(other),
|
| 424 |
|
- |
"a control holds no members: its body says what it is like",
|
|
437 |
+ |
"this holds no members: its body says what it is like",
|
| 425 |
438 |
|
)),
|
| 426 |
439 |
|
}
|
| 427 |
440 |
|
}
|
| 489 |
502 |
|
Ok(quote!(::quasi_router::Node::#member(#(#args),*)))
|
| 490 |
503 |
|
}
|
| 491 |
504 |
|
Emission::List(items) => list(items),
|
|
505 |
+ |
Emission::Form { action, body } => form(action, body),
|
|
506 |
+ |
Emission::Field { kind, .. } => Err(syn::Error::new(
|
|
507 |
+ |
kind.span(),
|
|
508 |
+ |
"a field is not a node: put it in a `form`",
|
|
509 |
+ |
)),
|
| 492 |
510 |
|
Emission::Row { .. } => Err(syn::Error::new(
|
| 493 |
511 |
|
emission_span(emission),
|
| 494 |
512 |
|
"a row is not a node: put it in a `list`",
|
| 569 |
587 |
|
)
|
| 570 |
588 |
|
}
|
| 571 |
589 |
|
|
|
590 |
+ |
/// The loop's binder, dereferenced where the declaration said to.
|
|
591 |
+ |
fn binder_pattern(dereferenced: bool, binder: &proc_macro2::Ident) -> TokenStream {
|
|
592 |
+ |
if dereferenced {
|
|
593 |
+ |
quote!(&#binder)
|
|
594 |
+ |
} else {
|
|
595 |
+ |
quote!(#binder)
|
|
596 |
+ |
}
|
|
597 |
+ |
}
|
|
598 |
+ |
|
|
599 |
+ |
/// One form: where it writes, what its button says, and what it asks.
|
|
600 |
+ |
fn form(action: &Action, body: &[Item]) -> Result<TokenStream> {
|
|
601 |
+ |
let mut submit = None;
|
|
602 |
+ |
let mut fields = Vec::new();
|
|
603 |
+ |
for item in body {
|
|
604 |
+ |
match item {
|
|
605 |
+ |
Item::Attribute { name, args } if name == "submit" => {
|
|
606 |
+ |
let [label] = args.as_slice() else {
|
|
607 |
+ |
return Err(syn::Error::new(name.span(), "`submit` says one thing"));
|
|
608 |
+ |
};
|
|
609 |
+ |
submit = Some(arg(label)?);
|
|
610 |
+ |
}
|
|
611 |
+ |
Item::Emit(Emission::Field {
|
|
612 |
+ |
kind,
|
|
613 |
+ |
name,
|
|
614 |
+ |
label,
|
|
615 |
+ |
body,
|
|
616 |
+ |
}) => fields.push(field(kind, name, label, body)?),
|
|
617 |
+ |
Item::Attribute { name, .. } => {
|
|
618 |
+ |
return Err(syn::Error::new(
|
|
619 |
+ |
name.span(),
|
|
620 |
+ |
"a form says `submit` and asks fields, and nothing else yet",
|
|
621 |
+ |
));
|
|
622 |
+ |
}
|
|
623 |
+ |
Item::Bind { name, .. } => {
|
|
624 |
+ |
return Err(syn::Error::new(name.span(), "a form binds nothing"));
|
|
625 |
+ |
}
|
|
626 |
+ |
Item::For { binder, .. } => {
|
|
627 |
+ |
return Err(syn::Error::new(
|
|
628 |
+ |
binder.span(),
|
|
629 |
+ |
"a form's fields are written out; a loop over them is not a production yet",
|
|
630 |
+ |
));
|
|
631 |
+ |
}
|
|
632 |
+ |
Item::Emit(other) => {
|
|
633 |
+ |
return Err(syn::Error::new(emission_span(other), "a form holds fields"));
|
|
634 |
+ |
}
|
|
635 |
+ |
}
|
|
636 |
+ |
}
|
|
637 |
+ |
let Some(submit) = submit else {
|
|
638 |
+ |
return Err(syn::Error::new(
|
|
639 |
+ |
action.verb.span(),
|
|
640 |
+ |
"a form says what its button reads: `submit <text>;`",
|
|
641 |
+ |
));
|
|
642 |
+ |
};
|
|
643 |
+ |
let action = self::action(action)?;
|
|
644 |
+ |
Ok(quote! {
|
|
645 |
+ |
::quasi_router::Node::Form {
|
|
646 |
+ |
action: #action,
|
|
647 |
+ |
submit: ::std::convert::Into::into(#submit),
|
|
648 |
+ |
fields: ::std::vec![#(#fields),*],
|
|
649 |
+ |
}
|
|
650 |
+ |
})
|
|
651 |
+ |
}
|
|
652 |
+ |
|
|
653 |
+ |
/// One field: what it asks for, by name, under a label.
|
|
654 |
+ |
fn field(kind: &proc_macro2::Ident, name: &Arg, label: &Arg, body: &[Item]) -> Result<TokenStream> {
|
|
655 |
+ |
let name = arg(name)?;
|
|
656 |
+ |
let label = arg(label)?;
|
|
657 |
+ |
accrete(
|
|
658 |
+ |
body,
|
|
659 |
+ |
Container::Field,
|
|
660 |
+ |
"e!(::quasi_router::Field::new(
|
|
661 |
+ |
::quasi_router::layout::FieldKind::#kind,
|
|
662 |
+ |
#name,
|
|
663 |
+ |
#label
|
|
664 |
+ |
)),
|
|
665 |
+ |
)
|
|
666 |
+ |
}
|
|
667 |
+ |
|
| 572 |
668 |
|
/// The rows of a list, built where they are read.
|
| 573 |
669 |
|
fn list(items: &[Item]) -> Result<TokenStream> {
|
| 574 |
670 |
|
let rows = format_ident!("rows", span = Span::call_site());
|
| 589 |
685 |
|
Ok(quote!(let #name = #value;))
|
| 590 |
686 |
|
}
|
| 591 |
687 |
|
Item::For {
|
|
688 |
+ |
dereferenced,
|
| 592 |
689 |
|
binder,
|
| 593 |
690 |
|
iterable,
|
| 594 |
691 |
|
body,
|
| 595 |
692 |
|
} => {
|
| 596 |
693 |
|
let iterable = hole(iterable)?;
|
| 597 |
694 |
|
let inner = list_statements(body, rows)?;
|
|
695 |
+ |
let binder = binder_pattern(*dereferenced, binder);
|
| 598 |
696 |
|
Ok(quote!(for #binder in #iterable { #(#inner)* }))
|
| 599 |
697 |
|
}
|
| 600 |
698 |
|
Item::Emit(Emission::Row { primary, body }) => {
|
| 651 |
749 |
|
target,
|
| 652 |
750 |
|
modifiers,
|
| 653 |
751 |
|
} = action;
|
| 654 |
|
- |
let verb = format_ident!("{}", verb);
|
| 655 |
|
- |
let target = match target {
|
| 656 |
|
- |
Some(target) => {
|
| 657 |
|
- |
let target = arg(target)?;
|
| 658 |
|
- |
quote!(#target)
|
| 659 |
|
- |
}
|
| 660 |
|
- |
None => quote!(),
|
|
752 |
+ |
let called = if verb == "doing" {
|
|
753 |
+ |
// Amendment 6: the supplier IS the action.
|
|
754 |
+ |
let Some(target) = target else {
|
|
755 |
+ |
return Err(syn::Error::new(verb.span(), "`doing` names a supplier"));
|
|
756 |
+ |
};
|
|
757 |
+ |
arg(target)?
|
|
758 |
+ |
} else {
|
|
759 |
+ |
let target = match target {
|
|
760 |
+ |
Some(target) => arg(target)?,
|
|
761 |
+ |
None => quote!(),
|
|
762 |
+ |
};
|
|
763 |
+ |
quote!(::quasi_router::Action::#verb(#target))
|
| 661 |
764 |
|
};
|
| 662 |
765 |
|
let modifiers = modifiers
|
| 663 |
766 |
|
.iter()
|
| 667 |
770 |
|
Ok(quote!(.#name(#(#args),*)))
|
| 668 |
771 |
|
})
|
| 669 |
772 |
|
.collect::<Result<Vec<_>>>()?;
|
| 670 |
|
- |
Ok(quote!(::quasi_router::Action::#verb(#target) #(#modifiers)*))
|
|
773 |
+ |
Ok(quote!(#called #(#modifiers)*))
|
| 671 |
774 |
|
}
|
| 672 |
775 |
|
|
| 673 |
776 |
|
fn source(source: &Source, owned: bool) -> Result<TokenStream> {
|
| 831 |
934 |
|
Emission::Simple { member, .. } => member.span(),
|
| 832 |
935 |
|
Emission::Screen { arrangement, .. } => arrangement.span(),
|
| 833 |
936 |
|
Emission::Row { .. } | Emission::List(_) => Span::call_site(),
|
|
937 |
+ |
Emission::Form { action, .. } => action.verb.span(),
|
|
938 |
+ |
Emission::Field { kind, .. } => kind.span(),
|
| 834 |
939 |
|
Emission::Act { action, .. } => action.verb.span(),
|
| 835 |
940 |
|
Emission::Guarded { guard, .. } => guard.span,
|
| 836 |
941 |
|
Emission::Given { .. } => Span::call_site(),
|