1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
use std::collections::{BTreeMap, HashSet};
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use rtfm_syntax::ast::App;
use crate::{
analyze::Analysis,
check::Extra,
codegen::{spawn_body, util},
};
/// Generates all `${ctxt}::Spawn` methods
pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream2> {
let mut items = vec![];
let mut seen = BTreeMap::<u8, HashSet<_>>::new();
for (spawner, spawnees) in app.spawn_callers() {
let sender = spawner.core(app);
let cfg_sender = util::cfg_core(sender, app.args.cores);
let seen = seen.entry(sender).or_default();
let mut methods = vec![];
for name in spawnees {
let spawnee = &app.software_tasks[name];
let receiver = spawnee.args.core;
let cfgs = &spawnee.cfgs;
let (args, _, untupled, ty) = util::regroup_inputs(&spawnee.inputs);
let args = &args;
if spawner.is_init() {
// `init` uses a special spawn implementation; it doesn't use the `spawn_${name}`
// functions which are shared by other contexts
let body = spawn_body::codegen(spawner, &name, app, analysis, extra);
let let_instant = if app.uses_schedule(receiver) {
let m = extra.monotonic();
Some(quote!(let instant = unsafe { <#m as rtfm::Monotonic>::zero() };))
} else {
None
};
let section = util::link_section("text", sender);
methods.push(quote!(
#(#cfgs)*
#section
fn #name(&self #(,#args)*) -> Result<(), #ty> {
#let_instant
#body
}
));
} else {
let spawn = util::spawn_ident(name, sender);
if !seen.contains(name) {
// generate a `spawn_${name}_S${sender}` function
seen.insert(name);
let instant = if app.uses_schedule(receiver) {
let m = extra.monotonic();
Some(quote!(, instant: <#m as rtfm::Monotonic>::Instant))
} else {
None
};
let body = spawn_body::codegen(spawner, &name, app, analysis, extra);
let section = util::link_section("text", sender);
items.push(quote!(
#cfg_sender
#(#cfgs)*
#section
unsafe fn #spawn(
priority: &rtfm::export::Priority
#instant
#(,#args)*
) -> Result<(), #ty> {
#body
}
));
}
let (let_instant, instant) = if app.uses_schedule(receiver) {
let m = extra.monotonic();
(
Some(if spawner.is_idle() {
quote!(let instant = <#m as rtfm::Monotonic>::now();)
} else {
quote!(let instant = self.instant();)
}),
Some(quote!(, instant)),
)
} else {
(None, None)
};
methods.push(quote!(
#(#cfgs)*
#[inline(always)]
fn #name(&self #(,#args)*) -> Result<(), #ty> {
unsafe {
#let_instant
#spawn(self.priority() #instant #(,#untupled)*)
}
}
));
}
}
let lt = if spawner.is_init() {
None
} else {
Some(quote!('a))
};
let spawner = spawner.ident(app);
debug_assert!(!methods.is_empty());
items.push(quote!(
#cfg_sender
impl<#lt> #spawner::Spawn<#lt> {
#(#methods)*
}
));
}
items
}
|