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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
//! Abstract Syntax Tree

use core::ops::Deref;
use std::collections::BTreeMap;

use syn::{Attribute, Expr, Ident, Pat, PatType, Path, Stmt, Type};

use crate::{Core, Map, Set};

/// The `#[app]` attribute
#[derive(Debug)]
pub struct App {
    /// The arguments to the `#[app]` attribute
    pub args: AppArgs,

    /// The name of the `const` item on which the `#[app]` attribute has been placed
    pub name: Ident,

    // NOTE one per core
    /// Per-core `#[init]` functions
    pub inits: Inits,

    /// Per-core `#[idle]` functions
    pub idles: Idles,

    /// Late (runtime initialized) resources
    pub late_resources: Map<LateResource>,

    /// Early (compile time initialized) resources
    pub resources: Map<Resource>,

    /// Hardware tasks: `#[task(binds = ..)]`s
    pub hardware_tasks: Map<HardwareTask>,

    /// Software tasks: `#[task]`
    pub software_tasks: Map<SoftwareTask>,

    /// Interrupts used to dispatch software tasks
    pub extern_interrupts: ExternInterrupts,

    pub(crate) _extensible: (),
}

/// Interrupts used to dispatch software tasks
pub type ExternInterrupts = BTreeMap<Core, Map<ExternInterrupt>>;

/// The arguments of the `#[app]` attribute
#[derive(Debug)]
pub struct AppArgs {
    /// The number of cores the application will use
    pub cores: u8,

    /// Custom arguments
    pub custom: Map<CustomArg>,
}

/// A custom argument
#[derive(Debug)]
pub enum CustomArg {
    /// A boolean: `true` or `false`
    Bool(bool),

    /// An unsuffixed, unsigned integer
    UInt(String),

    /// An item path
    Path(Path),
}

/// Per-core `init` functions
pub type Inits = BTreeMap<u8, Init>;
/// Per-core `idle` functions
pub type Idles = BTreeMap<u8, Idle>;

/// The `init`-ialization function
#[derive(Debug)]
pub struct Init {
    /// `init` context metadata
    pub args: InitArgs,

    /// Attributes that will apply to this `init` function
    pub attrs: Vec<Attribute>,

    /// The name of the `#[init]` function
    pub name: Ident,

    /// The context argument
    pub context: Box<Pat>,

    /// Whether this `init` function returns `LateResources` or not
    pub returns_late_resources: bool,

    /// Static variables local to this context
    pub locals: Map<Local>,
    /// The statements that make up this `init` function
    pub stmts: Vec<Stmt>,

    pub(crate) _extensible: (),
}

/// `init` context metadata
#[derive(Debug, Default)]
pub struct InitArgs {
    /// Which core this context belongs to?
    pub core: u8,

    /// Late resources that will be initialized by this core
    ///
    /// NOTE do not use this field for codegen; use `Analysis.late_resources` instead
    pub late: Set<Ident>,

    /// Resources that can be accessed from this context
    pub resources: Resources,

    /// Software tasks that can be spawned from this context
    pub spawn: Set<Ident>,

    /// Software tasks that can be scheduled from this context
    pub schedule: Set<Ident>,

    pub(crate) _extensible: (),
}

/// The `idle` context
#[derive(Debug)]
pub struct Idle {
    /// `idle` context metadata
    pub args: IdleArgs,

    /// Attributes that will apply to this `idle` function
    pub attrs: Vec<Attribute>,

    /// The name of the `#[idle]` function
    pub name: Ident,

    /// The context argument
    pub context: Box<Pat>,

    /// Static variables local to this context
    pub locals: Map<Local>,

    /// The statements that make up this `idle` function
    pub stmts: Vec<Stmt>,

    pub(crate) _extensible: (),
}

/// `idle` context metadata
#[derive(Debug)]
pub struct IdleArgs {
    /// Which core this context belongs to?
    pub core: u8,

    /// Resources that can be accessed from this context
    pub resources: Resources,

    /// Software tasks that can be spawned from this context
    pub spawn: Set<Ident>,

    /// Software tasks that can be scheduled from this context
    pub schedule: Set<Ident>,

    pub(crate) _extensible: (),
}

/// An early (compile time initialized) resource
#[derive(Debug)]
pub struct Resource {
    pub(crate) late: LateResource,
    /// The initial value of this resource
    pub expr: Box<Expr>,
}

impl Deref for Resource {
    type Target = LateResource;

    fn deref(&self) -> &LateResource {
        &self.late
    }
}

/// A late (runtime initialized) resource
#[derive(Debug)]
pub struct LateResource {
    /// `#[cfg]` attributes like `#[cfg(debug_assertions)]`
    pub cfgs: Vec<Attribute>,

    /// Attributes that will apply to this resource
    pub attrs: Vec<Attribute>,

    /// Whether this contains the `#[shared]` attribute or not
    ///
    /// NOTE: Always `false` in single core mode
    pub shared: bool,

    /// The type of this resource
    pub ty: Box<Type>,

    pub(crate) _extensible: (),
}

/// A software task
#[derive(Debug)]
pub struct SoftwareTask {
    /// Software task metadata
    pub args: SoftwareTaskArgs,

    /// `#[cfg]` attributes like `#[cfg(debug_assertions)]`
    pub cfgs: Vec<Attribute>,
    /// Attributes that will apply to this interrupt handler
    pub attrs: Vec<Attribute>,

    /// The context argument
    pub context: Box<Pat>,
    /// The inputs of this software task
    pub inputs: Vec<PatType>,

    /// Static variables local to this context
    pub locals: Map<Local>,
    /// The statements that make up the task handler
    pub stmts: Vec<Stmt>,

    pub(crate) _extensible: (),
}

/// Software task metadata
#[derive(Debug)]
pub struct SoftwareTaskArgs {
    /// The core this task will run on
    pub core: u8,

    /// The task capacity: the maximum number of pending messages that can be queued
    pub capacity: u8,

    /// The priority of this task
    pub priority: u8,

    /// Resources that can be accessed from this context
    pub resources: Resources,

    /// Software tasks that can be spawned from this context
    pub spawn: Set<Ident>,

    /// Software tasks that can be scheduled from this context
    pub schedule: Set<Ident>,

    pub(crate) _extensible: (),
}

impl Default for SoftwareTaskArgs {
    fn default() -> Self {
        Self {
            core: 0,
            capacity: 1,
            priority: 1,
            resources: Resources::new(),
            spawn: Set::new(),
            schedule: Set::new(),
            _extensible: (),
        }
    }
}

/// A hardware task
#[derive(Debug)]
pub struct HardwareTask {
    /// Hardware task metadata
    pub args: HardwareTaskArgs,

    /// Attributes that will apply to this interrupt handler
    pub attrs: Vec<Attribute>,

    /// The context argument
    pub context: Box<Pat>,

    /// Static variables local to this context
    pub locals: Map<Local>,
    /// The statements that make up the task handler
    pub stmts: Vec<Stmt>,

    pub(crate) _extensible: (),
}

/// Hardware task metadata
#[derive(Debug)]
pub struct HardwareTaskArgs {
    /// The core on which this task will be executed
    pub core: u8,

    /// The interrupt or exception that this task is bound to
    pub binds: Ident,

    /// The priority of this task
    pub priority: u8,

    /// Resources that can be accessed from this context
    pub resources: Resources,

    /// Software tasks that can be spawned from this context
    pub spawn: Set<Ident>,

    /// Software tasks that can be scheduled from this context
    pub schedule: Set<Ident>,

    pub(crate) _extensible: (),
}

/// Interrupt that could be used to dispatch software tasks
#[derive(Debug)]
pub struct ExternInterrupt {
    /// Attributes that will apply to this interrupt handler
    pub attrs: Vec<Attribute>,

    pub(crate) _extensible: (),
}

/// A `static mut` variable local to and owned by a context
#[derive(Debug)]
pub struct Local {
    /// Attributes like `#[link_section]`
    pub attrs: Vec<Attribute>,

    /// `#[cfg]` attributes like `#[cfg(debug_assertions)]`
    pub cfgs: Vec<Attribute>,

    /// Whether this contains the `#[shared]` attribute or not
    ///
    /// NOTE: Always `false` in single core mode
    pub shared: bool,

    /// Type
    pub ty: Box<Type>,

    /// Initial value
    pub expr: Box<Expr>,

    pub(crate) _extensible: (),
}

/// Resource access
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Access {
    /// `[x]`
    Exclusive,

    /// `[&x]`
    Shared,
}

impl Access {
    /// Is this enum in the `Exclusive` variant?
    pub fn is_exclusive(&self) -> bool {
        *self == Access::Exclusive
    }

    /// Is this enum in the `Shared` variant?
    pub fn is_shared(&self) -> bool {
        *self == Access::Shared
    }
}

/// Resource access list
pub type Resources = Map<Access>;