ocl_include/
node.rs

1use std::{
2    cmp::Ordering,
3    ops::Range,
4    path::{Path, PathBuf},
5    rc::Rc,
6};
7
8#[derive(Debug)]
9struct IndexEntry {
10    name: Rc<PathBuf>,
11    start: usize,
12    range: Range<usize>,
13}
14
15/// Index that maps generated code locations to their origins
16pub struct Index {
17    segs: Vec<IndexEntry>,
18    size: usize,
19}
20
21impl Index {
22    fn new() -> Self {
23        Self {
24            segs: Vec::new(),
25            size: 0,
26        }
27    }
28
29    fn push(&mut self, name: Rc<PathBuf>, start: usize, size: usize) {
30        self.segs.push(IndexEntry {
31            name,
32            start,
33            range: self.size..(self.size + size),
34        });
35        self.size += size;
36    }
37
38    fn append(&mut self, mut index: Index) {
39        for seg in index.segs.iter_mut() {
40            let r = &mut seg.range;
41            r.start += self.size;
42            r.end += self.size;
43        }
44        self.segs.append(&mut index.segs);
45        self.size += index.size;
46    }
47
48    /// Maps line number in generated code to source file name and position in it
49    pub fn search(&self, pos: usize) -> Option<(PathBuf, usize)> {
50        match self.segs.binary_search_by(|seg| {
51            if pos < seg.range.start {
52                Ordering::Greater
53            } else if pos >= seg.range.end {
54                Ordering::Less
55            } else {
56                Ordering::Equal
57            }
58        }) {
59            Ok(i) => {
60                let seg = &self.segs[i];
61                Some(((*seg.name).clone(), pos - seg.range.start + seg.start))
62            }
63            Err(_) => None,
64        }
65    }
66}
67
68/// Tree of parsed source files
69pub struct Node {
70    name: PathBuf,
71    inner: Vec<(Node, usize)>,
72    text: String,
73    index: Vec<Range<usize>>,
74}
75
76impl Node {
77    pub(crate) fn new(name: &Path) -> Self {
78        Self {
79            name: name.to_path_buf(),
80            inner: Vec::new(),
81            text: String::new(),
82            index: Vec::new(),
83        }
84    }
85
86    pub fn name(&self) -> &Path {
87        &self.name
88    }
89
90    pub(crate) fn add_line(&mut self, line: &str) {
91        let plen = self.text.len();
92        self.text.push_str(line.trim_end());
93        self.text.push('\n');
94        self.index.push(plen..self.text.len());
95    }
96
97    pub(crate) fn add_child(&mut self, node: Node) {
98        self.add_line("");
99        self.inner.push((node, self.index.len() - 1));
100    }
101
102    pub fn lines_count(&self) -> usize {
103        self.index.len()
104    }
105
106    /// Generates resulting code string and mapping index for it
107    pub fn collect(&self) -> (String, Index) {
108        let mut accum = String::new();
109        let mut index = Index::new();
110
111        let name = Rc::new(self.name.clone());
112
113        let mut ppos = 0;
114        for (node, pos) in self.inner.iter() {
115            let start = self.index[ppos].start;
116            let end = self.index[*pos].end;
117
118            accum.push_str(&self.text[start..end]);
119            index.push(name.clone(), ppos, pos - ppos + 1);
120
121            let (child_str, child_index) = node.collect();
122            accum.push_str(&child_str);
123            index.append(child_index);
124
125            ppos = *pos + 1;
126        }
127
128        if ppos < self.index.len() {
129            accum.push_str(&self.text[self.index[ppos].start..]);
130            index.push(name, ppos, self.index.len() - ppos);
131        }
132
133        (accum, index)
134    }
135}