r3_core 0.1.4

R3-OS API definition
Documentation
//! Interrupt lines and handlers
use core::{fmt, hash, marker::PhantomData};

use super::{
    raw, raw_cfg, Cfg, ClearInterruptLineError, EnableInterruptLineError, PendInterruptLineError,
    QueryInterruptLineError, SetInterruptLinePriorityError,
};
use crate::{
    closure::{Closure, IntoClosureConst},
    utils::{for_times::Nat, slice_sort_unstable_by, ComptimeVec, Init, PhantomInvariant},
};

pub use raw::{InterruptNum, InterruptPriority};

// ----------------------------------------------------------------------------

/// Refers to an interrupt line in a system.
pub struct InterruptLine<System: raw::KernelInterruptLine>(InterruptNum, PhantomInvariant<System>);

impl<System: raw::KernelInterruptLine> Clone for InterruptLine<System> {
    #[inline]
    fn clone(&self) -> Self {
        Self(self.0, self.1)
    }
}

impl<System: raw::KernelInterruptLine> Copy for InterruptLine<System> {}

impl<System: raw::KernelInterruptLine> PartialEq for InterruptLine<System> {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        self.0 == other.0
    }
}

impl<System: raw::KernelInterruptLine> Eq for InterruptLine<System> {}

impl<System: raw::KernelInterruptLine> hash::Hash for InterruptLine<System> {
    #[inline]
    fn hash<H>(&self, state: &mut H)
    where
        H: hash::Hasher,
    {
        hash::Hash::hash(&self.0, state);
    }
}

impl<System: raw::KernelInterruptLine> fmt::Debug for InterruptLine<System> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("InterruptLine").field(&self.0).finish()
    }
}

impl<System: raw::KernelInterruptLine> InterruptLine<System> {
    /// Construct a `InterruptLine` from `InterruptNum`.
    #[inline]
    pub const fn from_num(num: InterruptNum) -> Self {
        Self(num, Init::INIT)
    }

    /// Get the raw `InterruptNum` value representing this interrupt line.
    #[inline]
    pub const fn num(self) -> InterruptNum {
        self.0
    }
}

impl<System: raw::KernelInterruptLine> InterruptLine<System> {
    /// Construct a `InterruptLineDefiner` to define an interrupt line in [a
    /// configuration function](crate#static-configuration).
    pub const fn define() -> InterruptLineDefiner<System> {
        InterruptLineDefiner::new()
    }

    /// Set the priority of the interrupt line. The new priority must fall
    /// within [a managed range].
    ///
    /// Turning a managed interrupt handler into an unmanaged one is unsafe
    /// because the behavior of system calls is undefined inside an unmanaged
    /// interrupt handler. This method checks the new priority to prevent this
    /// from happening and returns [`SetInterruptLinePriorityError::BadParam`]
    /// if the operation is unsafe.
    ///
    /// [a managed range]: crate::kernel::raw::KernelInterruptLine::RAW_MANAGED_INTERRUPT_PRIORITY_RANGE
    #[inline(never)]
    pub fn set_priority(
        self,
        value: InterruptPriority,
    ) -> Result<(), SetInterruptLinePriorityError> {
        // Deny unmanaged priority
        if !System::RAW_MANAGED_INTERRUPT_PRIORITY_RANGE.contains(&value) {
            return Err(SetInterruptLinePriorityError::BadParam);
        }

        // Safety: `value` falls within the managed range.
        unsafe { self.set_priority_unchecked(value) }
    }

    /// Set the priority of the interrupt line without checking if the new
    /// priority falls within [a managed range].
    ///
    /// [a managed range]: crate::kernel::raw::KernelInterruptLine::RAW_MANAGED_INTERRUPT_PRIORITY_RANGE
    ///
    /// # Safety
    ///
    /// If a non-[unmanaged-safe] interrupt handler is attached to the interrupt
    /// line, changing the priority of the interrupt line to outside of the
    /// managed range (thus turning the handler into an unmanaged handler) may
    /// allow the interrupt handler to invoke an undefined behavior, for
    /// example, by making system calls, which are disallowed in an unmanaged
    /// interrupt handler.
    ///
    /// [unmanaged-safe]: InterruptHandlerDefiner::unmanaged
    #[inline]
    pub unsafe fn set_priority_unchecked(
        self,
        value: InterruptPriority,
    ) -> Result<(), SetInterruptLinePriorityError> {
        // Safety: `InterruptLine` represents a permission to access the
        //         referenced object.
        unsafe { System::raw_interrupt_line_set_priority(self.0, value) }
    }

    /// Enable the interrupt line.
    #[inline]
    pub fn enable(self) -> Result<(), EnableInterruptLineError> {
        // Safety: `InterruptLine` represents a permission to access the
        //         referenced object.
        unsafe { System::raw_interrupt_line_enable(self.0) }
    }

    /// Disable the interrupt line.
    #[inline]
    pub fn disable(self) -> Result<(), EnableInterruptLineError> {
        // Safety: `InterruptLine` represents a permission to access the
        //         referenced object.
        unsafe { System::raw_interrupt_line_disable(self.0) }
    }

    /// Set the pending flag of the interrupt line.
    #[inline]
    pub fn pend(self) -> Result<(), PendInterruptLineError> {
        // Safety: `InterruptLine` represents a permission to access the
        //         referenced object.
        unsafe { System::raw_interrupt_line_pend(self.0) }
    }

    /// Clear the pending flag of the interrupt line.
    #[inline]
    pub fn clear(self) -> Result<(), ClearInterruptLineError> {
        // Safety: `InterruptLine` represents a permission to access the
        //         referenced object.
        unsafe { System::raw_interrupt_line_clear(self.0) }
    }

    /// Read the pending flag of the interrupt line.
    #[inline]
    pub fn is_pending(self) -> Result<bool, QueryInterruptLineError> {
        // Safety: `InterruptLine` represents a permission to access the
        //         referenced object.
        unsafe { System::raw_interrupt_line_is_pending(self.0) }
    }
}

// ----------------------------------------------------------------------------

/// Represents a registered (second-level) interrupt handler in a system.
///
/// There are no operations defined for interrupt handlers, so this type
/// is only used for [static configuration][1].
///
/// [1]: crate#static-configuration
pub struct StaticInterruptHandler<System: raw::KernelInterruptLine>(PhantomInvariant<System>);

// TODO: A dynamically registered interrupt handler would be `InterruptHandler`,
//       which would hold an ID to delete later.

impl<System: raw::KernelInterruptLine> fmt::Debug for StaticInterruptHandler<System> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("InterruptHandler")
    }
}

impl<System: raw::KernelInterruptLine> Clone for StaticInterruptHandler<System> {
    #[inline]
    fn clone(&self) -> Self {
        Self(self.0)
    }
}

impl<System: raw::KernelInterruptLine> Copy for StaticInterruptHandler<System> {}

impl<System: raw::KernelInterruptLine> StaticInterruptHandler<System> {
    const fn new() -> Self {
        Self(PhantomData)
    }

    /// Construct a `InterruptHandlerDefiner` to define an interrupt handler in
    /// [a configuration function](crate#static-configuration).
    pub const fn define() -> InterruptHandlerDefiner<System> {
        InterruptHandlerDefiner::new()
    }
}

// ----------------------------------------------------------------------------

/// The definer (static builder) for [`InterruptLine`].
#[must_use = "must call `finish()` to complete registration"]
pub struct InterruptLineDefiner<System: raw::KernelInterruptLine> {
    _phantom: PhantomInvariant<System>,
    line: Option<InterruptNum>,
    priority: Option<InterruptPriority>,
    enabled: bool,
}

impl<System: raw::KernelInterruptLine> InterruptLineDefiner<System> {
    const fn new() -> Self {
        Self {
            _phantom: Init::INIT,
            line: None,
            priority: None,
            enabled: false,
        }
    }

    /// \[**Required**\] Specify the interrupt line to confiigure.
    pub const fn line(self, line: InterruptNum) -> Self {
        assert!(self.line.is_none(), "`line` is specified twice");
        Self {
            line: Some(line),
            ..self
        }
    }

    /// Specify the initial priority.
    pub const fn priority(self, priority: InterruptPriority) -> Self {
        assert!(self.priority.is_none(), "`priority` is specified twice");
        Self {
            priority: Some(priority),
            ..self
        }
    }

    /// Specify whether the interrupt linie should be enabled at system startup.
    /// Defaults to `false` (disabled).
    pub const fn enabled(self, enabled: bool) -> Self {
        Self { enabled, ..self }
    }

    /// Complete the configuration of an interrupt line, returning an
    /// `InterruptLine` object.
    pub const fn finish<C: ~const raw_cfg::CfgInterruptLine<System = System>>(
        self,
        cfg: &mut Cfg<C>,
    ) -> InterruptLine<System> {
        let line_num = self.line.expect("`line` is not specified");

        // Create a `CfgBuilderInterruptLine` for `line_num` if it doesn't exist
        // yet
        let i = if let Some(i) = vec_position!(cfg.interrupt_lines, |il| il.num == line_num) {
            i
        } else {
            cfg.interrupt_lines.push(CfgInterruptLineInfo {
                num: line_num,
                priority: None,
                enabled: false,
            });
            cfg.interrupt_lines.len() - 1
        };

        // Update `CfgBuilderInterruptLine` with values from `self`
        let cfg_interrupt_line = &mut cfg.interrupt_lines[i];

        if let Some(priority) = self.priority {
            assert!(
                cfg_interrupt_line.priority.is_none(),
                "`priority` is already specified for this interrupt line"
            );
            cfg_interrupt_line.priority = Some(priority);
        }

        if self.enabled {
            cfg_interrupt_line.enabled = true;
        }

        InterruptLine::from_num(line_num)
    }
}

// ----------------------------------------------------------------------------

/// The definer (static builder) for [`StaticInterruptHandler`].
pub struct InterruptHandlerDefiner<System: raw::KernelInterruptLine> {
    _phantom: PhantomInvariant<System>,
    line: Option<InterruptNum>,
    start: Option<Closure>,
    priority: i32,
    unmanaged: bool,
}

impl<System: raw::KernelInterruptLine> InterruptHandlerDefiner<System> {
    const fn new() -> Self {
        Self {
            _phantom: Init::INIT,
            line: None,
            start: None,
            priority: 0,
            unmanaged: false,
        }
    }

    /// \[**Required**\] Specify the entry point.
    pub const fn start<C: ~const IntoClosureConst>(self, start: C) -> Self {
        Self {
            start: Some(start.into_closure_const()),
            ..self
        }
    }

    /// \[**Required**\] Specify the interrupt line to attach the interrupt
    /// handler to.
    pub const fn line(self, line: InterruptNum) -> Self {
        assert!(self.line.is_none(), "`line` is specified twice");
        Self {
            line: Some(line),
            ..self
        }
    }

    /// Specify the priority. Defaults to `0` when unspecified.
    ///
    /// When multiple handlers are registered to a single interrupt line, those
    /// with smaller priority values will execute earlier.
    ///
    /// This should not be confused with [an interrupt line's priority].
    ///
    /// [an interrupt line's priority]: InterruptLineDefiner::priority
    pub const fn priority(self, priority: i32) -> Self {
        Self { priority, ..self }
    }

    /// Indicate that the entry point function is unmanaged-safe (designed to
    /// execute as [an unmanaged interrupt handler]).
    ///
    /// If an interrupt line is not configured with an initial priority value
    /// that falls within [a managed range], configuration will fail unless
    /// all of its attached interrupt handlers are marked as
    /// unmanaged-safe.
    ///
    /// [a managed range]: crate::kernel::raw::KernelInterruptLine::RAW_MANAGED_INTERRUPT_PRIORITY_RANGE
    ///
    /// # Safety
    ///
    /// The behavior of system calls is undefined in an unmanaged interrupt
    /// handler.
    ///
    /// [an unmanaged interrupt handler]: crate#interrupt-handling-framework
    pub const unsafe fn unmanaged(self) -> Self {
        Self {
            unmanaged: true,
            ..self
        }
    }

    /// Complete the registration of an interrupt handler, returning an
    /// `StaticInterruptHandler` object.
    pub const fn finish<C: ~const raw_cfg::CfgInterruptLine<System = System>>(
        self,
        cfg: &mut Cfg<C>,
    ) -> StaticInterruptHandler<System> {
        let line_num = self.line.expect("`line` is not specified");

        // Add a `CfgInterruptLineInfo` at the same time
        InterruptLine::define().line(line_num).finish(cfg);

        let order = cfg.interrupt_handlers.len();
        cfg.interrupt_handlers.push(CfgInterruptHandler {
            line: line_num,
            start: self.start.expect("`start` is not specified"),
            priority: self.priority,
            unmanaged: self.unmanaged,
            order,
        });

        StaticInterruptHandler::new()
    }
}

// ----------------------------------------------------------------------------

/// Describes an interrupt line in `Cfg`.
///
/// This type has an intentionally inconsistent name lest it collide with
/// `raw_cfg::CfgInterruptLine`.
#[doc(hidden)]
#[derive(Debug, Clone, Copy)]
pub(super) struct CfgInterruptLineInfo {
    pub(super) num: InterruptNum,
    pub(super) priority: Option<InterruptPriority>,
    pub(super) enabled: bool,
}

impl CfgInterruptLineInfo {
    /// Return `true` if the interrupt line is configured with a priority value
    /// that falls within a managed range.
    const fn is_initially_managed<System: raw::KernelInterruptLine>(&self) -> bool {
        if let Some(priority) = self.priority {
            let range = System::RAW_MANAGED_INTERRUPT_PRIORITY_RANGE;
            priority >= range.start && priority < range.end
        } else {
            false
        }
    }
}

// ----------------------------------------------------------------------------

#[doc(hidden)]
#[derive(Debug, Clone, Copy)]
pub struct CfgInterruptHandler {
    line: InterruptNum,
    start: Closure,
    priority: i32,
    unmanaged: bool,
    /// The registration order.
    order: usize,
}

/// Panic if a non-unmanaged-safe interrupt handler is attached to an
/// interrupt line that is not known to be managed.
pub(super) const fn panic_if_unmanaged_safety_is_violated<System: raw::KernelInterruptLine>(
    interrupt_lines: &ComptimeVec<CfgInterruptLineInfo>,
    interrupt_handlers: &ComptimeVec<CfgInterruptHandler>,
) {
    // `for` is unusable in `const fn` [ref:const_for]
    let mut i = 0;
    while i < interrupt_handlers.len() {
        let handler = &interrupt_handlers[i];
        i += 1;
        if handler.unmanaged {
            continue;
        }

        let is_line_assumed_managed = {
            let lines = System::RAW_MANAGED_INTERRUPT_LINES;
            let mut i = 0;
            loop {
                if i < lines.len() {
                    if lines[i] == handler.line {
                        break true;
                    }
                    i += 1;
                } else {
                    break false;
                }
            }
        };

        let managed_line_i = vec_position!(interrupt_lines, |line| line.num == handler.line
            && line.is_initially_managed::<System>());
        let is_line_managed = managed_line_i.is_some() || is_line_assumed_managed;

        assert!(
            is_line_managed,
            "An interrupt handler that is not marked with `unmanaged` \
            is attached to an interrupt line whose priority value is \
            unspecified or doesn't fall within a managed range."
        );
    }
}

/// Sort interrupt handlers by (interrupt number, priority, order).
pub(super) const fn sort_handlers(interrupt_handlers: &mut ComptimeVec<CfgInterruptHandler>) {
    slice_sort_unstable_by(
        interrupt_handlers.as_mut_slice(),
        closure!(|x: &CfgInterruptHandler, y: &CfgInterruptHandler| -> bool {
            if x.line != y.line {
                x.line < y.line
            } else if x.priority != y.priority {
                x.priority < y.priority
            } else {
                x.order < y.order
            }
        }),
    );
}

/// A combined second-level interrupt handler.
///
/// # Safety
///
/// Only meant to be called from a first-level interrupt handler. CPU Lock must
/// be inactive.
pub type InterruptHandlerFn = unsafe extern "C" fn();

/// The precursor of combined second-level interrupt handlers.
///
/// `MakeCombinedHandlers` generates `ProtoCombinedHandlerFn` for each
/// given (uncombined) interrupt handler. Each `ProtoCombinedHandlerFn` calls
/// the handler. Then, it proceeds to the next `ProtoCombinedHandlerFn` and this
/// goes on until it calls the last handler of the current interrupt number.
///
/// ```rust,ignore
/// // `MakeCombinedHandlersTrait::PROTO_COMBINED_HANDLERS`
/// #[inline(always)]
/// fn proto_combined_handler_0(/* ... */) {
///     HANDLERS[0].call();
///     if 1 >= HANDLERS.len() || HANDLERS[0].line != HANDLERS[1].line {
///         return;
///     }
///     proto_combined_handler_1(cur_line, /* ... */);
/// }
/// fn proto_combined_handler_1(...) { /* ... */ }
/// fn proto_combined_handler_2(...) { /* ... */ }
/// ```
///
/// `ProtoCombinedHandlerFn` is created from a function that is marked as
/// `#[inline(always)]`. This ensures the chained calls between
/// `ProtoCombinedHandlerFn`s don't appear in the final binary, assuming some
/// level of compiler optimization is in place.
///
/// The final product of `MakeCombinedHandlers` is a combined second-level
/// interrupt handler for each interrupt number, which calls the first
/// `ProtoCombinedHandlerFn` of that interrupt number.
///
/// ```rust,ignore
/// // `MakeCombinedHandlersTrait::COMBINED_HANDLERS`
/// extern "C" fn combined_handler_for_line_3() {
///     proto_combined_handler_2(/* ... */);
/// }
/// ```
///
/// Because of inlining, the above code is optimized as follows:
///
/// ```rust,ignore
/// extern "C" fn combined_handler_for_line_3() {
///     HANDLERS[2].call();
///     HANDLERS[3].call();
/// }
/// ```
type ProtoCombinedHandlerFn = fn();

/// A static list of [`CfgInterruptHandler`]s.
#[doc(hidden)]
pub trait CfgInterruptHandlerList {
    /// `U<Self::NUM_HANDLERS>`
    type NumHandlers: Nat;
    const HANDLERS: &'static [CfgInterruptHandler];
}

/// The ultimate purpose of this type is to make `COMBINED_HANDLERS`
/// (a list of `InterruptHandlerFn`s) available to
/// `new_interrupt_handler_table`.
struct MakeCombinedHandlers<System, Handlers, const NUM_HANDLERS: usize>(
    PhantomInvariant<(System, Handlers)>,
);

trait MakeCombinedHandlersTrait {
    type System: raw::KernelBase;
    type NumHandlers: Nat;
    const HANDLERS: &'static [CfgInterruptHandler];
    const NUM_HANDLERS: usize;
    const PROTO_COMBINED_HANDLERS: &'static [ProtoCombinedHandlerFn];
    const COMBINED_HANDLERS: &'static [Option<InterruptHandlerFn>];
}

impl<System: raw::KernelBase, Handlers: CfgInterruptHandlerList, const NUM_HANDLERS: usize>
    MakeCombinedHandlersTrait for MakeCombinedHandlers<System, Handlers, NUM_HANDLERS>
{
    type System = System;
    type NumHandlers = Handlers::NumHandlers;
    const HANDLERS: &'static [CfgInterruptHandler] = Handlers::HANDLERS;
    const NUM_HANDLERS: usize = NUM_HANDLERS;
    const PROTO_COMBINED_HANDLERS: &'static [ProtoCombinedHandlerFn] =
        &Self::PROTO_COMBINED_HANDLERS_ARRAY;
    const COMBINED_HANDLERS: &'static [Option<InterruptHandlerFn>] = &Self::COMBINED_HANDLERS_ARRAY;
}

impl<System: raw::KernelBase, Handlers: CfgInterruptHandlerList, const NUM_HANDLERS: usize>
    MakeCombinedHandlers<System, Handlers, NUM_HANDLERS>
{
    const PROTO_COMBINED_HANDLERS_ARRAY: [ProtoCombinedHandlerFn; NUM_HANDLERS] = {
        const_array_from_fn! {
            fn iter<[T: MakeCombinedHandlersTrait], I: Nat>(ref mut cell: T) -> ProtoCombinedHandlerFn {
                #[inline(always)]
                fn proto_combined_handler<T: MakeCombinedHandlersTrait, I: Nat>() {
                    let handler = T::HANDLERS[I::N];

                    handler.start.call();

                    let next_i = I::N + 1;
                    if next_i >= T::NUM_HANDLERS || T::HANDLERS[next_i].line != handler.line {
                        return;
                    }

                    // Relinquish CPU Lock before calling the next handler
                    use raw::KernelBase;
                    if T::System::raw_has_cpu_lock() {
                        // Safety: CPU Lock active, we have the ownership
                        // of the current CPU Lock (because a previously
                        // called handler left it active)
                        let _ = unsafe { T::System::raw_release_cpu_lock() };
                    }

                    // Call the next proto combined handler
                    T::PROTO_COMBINED_HANDLERS[next_i]();
                }
                proto_combined_handler::<T, I>
            }

            // `Self: MakeCombinedHandlersTrait` is used as the context type
            // for the iteration
            (0..NUM_HANDLERS).map(|i| iter::<[Self], i>(Self(PhantomData))).collect::<[_; Handlers::NumHandlers]>()
        }
    };

    const COMBINED_HANDLERS_ARRAY: [Option<InterruptHandlerFn>; NUM_HANDLERS] = {
        const_array_from_fn! {
            fn iter<[T: MakeCombinedHandlersTrait], I: Nat>(ref mut cell: T) -> Option<InterruptHandlerFn> {
                extern "C" fn combined_handler<T: MakeCombinedHandlersTrait, I: Nat>() {
                    T::PROTO_COMBINED_HANDLERS[I::N]();
                }

                let handler = T::HANDLERS[I::N];
                let is_first_handler_of_line = if I::N == 0 {
                    true
                } else {
                    T::HANDLERS[I::N - 1].line != handler.line
                };

                if is_first_handler_of_line {
                    Some(combined_handler::<T, I> as InterruptHandlerFn)
                } else {
                    None
                }
            }

            // `Self: MakeCombinedHandlersTrait` is used as the context type
            // for the iteration
            (0..NUM_HANDLERS).map(|i| iter::<[Self], i>(Self(PhantomData))).collect::<[_; Handlers::NumHandlers]>()
        }
    };
}

/// Construct a table of combined second-level interrupt handlers. Only meant to
/// be used by `attach_static!`
#[doc(hidden)]
pub const unsafe fn new_interrupt_handler_table<
    System: raw::KernelBase,
    NumLines: Nat,
    Handlers: CfgInterruptHandlerList,
    const NUM_LINES: usize,
    const NUM_HANDLERS: usize,
>() -> [Option<InterruptHandlerFn>; NUM_LINES] {
    // Check generic parameters

    // Actually, these equality is automatically checked by
    // `const_array_from_fn!`, but do the check here as well to clarify
    // this function's precondition.
    //
    // `assert_eq!` not supported in a const context yet [ref:const_assert_eq]
    assert!(NumLines::N == NUM_LINES);
    assert!(Handlers::NumHandlers::N == NUM_HANDLERS);

    // `for` is unusable in `const fn` [ref:const_for]
    let mut i = 0;
    while i < NUM_HANDLERS {
        let handler = Handlers::HANDLERS[i];
        assert!(handler.line < NUM_LINES);
        i += 1;
    }

    const_array_from_fn! {
        fn iter<[T: MakeCombinedHandlersTrait], I: Nat>(ref mut cell: T) -> Option<InterruptHandlerFn> {
            // The interrupt line
            let line = I::N;

            // Find the first handler for the line. The elements of
            // `COMBINED_HANDLERS` are only set for the first handler of each
            // line.
            let i = lower_bound!(T::NUM_HANDLERS, |i| T::HANDLERS[i].line < line);

            if i >= T::NUM_HANDLERS || T::HANDLERS[i].line != line {
                // The interrupt line does not have an associated handler
                None
            } else {
                // Return the combined handler
                let handler = T::COMBINED_HANDLERS[i];
                assert!(handler.is_some());
                handler
            }
        }

        (0..NUM_LINES).map(|i| iter::<[MakeCombinedHandlers<
            System,
            Handlers,
            NUM_HANDLERS,
        >], i>(MakeCombinedHandlers(PhantomData))).collect::<[_; NumLines]>()
    }
}

#[doc(hidden)]
pub const fn num_required_interrupt_line_slots(handlers: &[CfgInterruptHandler]) -> usize {
    // `for` is unusable in `const fn` [ref:const_for]
    let mut i = 0;
    let mut out = 0;
    while i < handlers.len() {
        if handlers[i].line + 1 > out {
            out = handlers[i].line + 1;
        }
        i += 1;
    }
    out
}