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
// generated by lelwel

mod imp;

pub use imp::*;

use super::diag::*;
use super::parser::*;
use super::token::*;
use bumpalo::Bump;
use std::cell::Cell;

/// Abstract syntax tree

#[derive(Debug)]
pub struct Ast<'a, Input: TokenStream> {
    arena: Bump,
    root: Option<&'a <Parser as Parsing<'a, Input>>::Output>,
}

impl<'a, Input: TokenStream> Ast<'a, Input> {
    /// Creates a new abstract syntax tree.
    pub fn new(input: &mut Input, diag: &mut Diag) -> Ast<'a, Input> {
        let mut ast = Ast {
            arena: Bump::new(),
            root: None,
        };
        // borrow arena for the lifetime of the returned Ast
        match Parser::parse(input, Self::extend(&ast.arena), diag) {
            Ok(root) => ast.root = Some(Self::extend(ast.arena.alloc(root))),
            Err(e) => diag.error(e, input.current().range),
        }
        ast
    }

    /// Gets the root node of the `Ast`.
    #[allow(dead_code)]
    pub fn root(&self) -> Option<&'a <Parser as Parsing<'a, Input>>::Output> {
        self.root
    }

    /// Extends lifetime of reference to lifetime of `Ast`.
    #[allow(dead_code)]
    fn extend<'b, T>(reference: &'b T) -> &'a T {
        unsafe { &*(reference as *const T) }
    }
}

/// Reference to another node in the `Ast`.
pub struct Ref<'a, T> {
    target: Cell<Option<&'a T>>,
}

#[allow(dead_code)]
impl<'a, T> Ref<'a, T> {
    /// Creates a new `Ref`.
    pub fn new(init: Option<&'a T>) -> Ref<'a, T> {
        Ref {
            target: Cell::new(init),
        }
    }

    /// Sets the target of the `Ref`.
    pub fn set(&self, value: &'a T) {
        self.target.set(Some(value));
    }

    /// Gets the target of the `Ref`.
    pub fn get(&self) -> Option<&'a T> {
        self.target.get()
    }
}

impl<'a, T> std::fmt::Debug for Ref<'a, T> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let ptr = match self.get() {
            Some(e) => e,
            None => std::ptr::null(),
        };
        std::fmt::Pointer::fmt(&ptr, f)
    }
}

impl<'a, T> std::fmt::Pointer for Ref<'a, T> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let ptr = match self.get() {
            Some(e) => e,
            None => std::ptr::null(),
        };
        std::fmt::Pointer::fmt(&ptr, f)
    }
}