hemtt_preprocessor/
map.rs1use std::path::PathBuf;
2
3use hemtt_tokens::{Symbol, Token};
4use serde::Serialize;
5
6pub struct Processed {
8 sources: Vec<(String, String)>,
9 mappings: Vec<Vec<Mapping>>,
10 output: String,
11}
12
13impl Processed {
14 #[must_use]
15 pub fn output(&self) -> &str {
17 &self.output
18 }
19
20 #[must_use]
21 pub fn get_source_map(&self, processed: PathBuf) -> String {
27 #[derive(Serialize)]
28 struct Intermediate {
29 version: u8,
30 file: PathBuf,
31 sources: Vec<String>,
32 names: Vec<()>,
33 mappings: Vec<Vec<(usize, usize, usize, usize)>>,
34 }
35 serde_json::to_string(&Intermediate {
36 version: 3,
37 names: Vec::new(),
38 file: processed,
39 sources: self.sources.iter().map(|(path, _)| path.clone()).collect(),
40 mappings: {
41 self.mappings
42 .iter()
43 .map(|o| {
44 o.iter()
45 .map(|i| {
46 (
47 i.processed_column,
48 i.source,
49 i.original_line,
50 i.original_column,
51 )
52 })
53 .collect::<Vec<(usize, usize, usize, usize)>>()
54 })
55 .collect::<Vec<Vec<(usize, usize, usize, usize)>>>()
56 },
57 })
58 .unwrap()
59 }
60}
61
62#[allow(clippy::fallible_impl_from)] impl From<Vec<Token>> for Processed {
64 fn from(tokens: Vec<Token>) -> Self {
65 let mut sources: Vec<(String, String)> = Vec::new();
66 let mut mappings = Vec::new();
67 let mut output = String::new();
68 let mut mapping = Vec::new();
69 let mut next_offset = 0;
70 for token in tokens {
71 let source = token.source();
72 let symbol = token.symbol();
73 let render = symbol.output();
74 if render.is_empty() {
75 continue;
76 }
77 let original_line = source.start().1 .0;
78 let original_column = source.start().1 .1;
79 let source = sources
80 .iter()
81 .position(|(name, _)| name == &source.path().to_string())
82 .map_or_else(
83 || {
84 sources.push((source.path().to_string(), {
85 if source.path() == "%builtin%" {
86 String::new()
87 } else {
88 std::fs::read_to_string(source.path()).unwrap()
89 }
90 }));
91 sources.len() - 1
92 },
93 |index| index,
94 );
95 if symbol == &Symbol::Newline {
96 mappings.push(mapping);
97 mapping = Vec::new();
98 next_offset = 0;
99 } else {
100 mapping.push(Mapping {
101 processed_column: next_offset,
102 source,
103 original_line,
104 original_column,
105 });
106 next_offset = render.len();
107 }
108 output.push_str(render.as_str());
109 }
110 Self {
111 sources,
112 mappings,
113 output,
114 }
115 }
116}
117
118pub struct Mapping {
120 processed_column: usize,
121 source: usize,
122 original_line: usize,
123 original_column: usize,
124}
125
126impl Mapping {
127 #[must_use]
128 pub const fn processed_column(&self) -> usize {
130 self.processed_column
131 }
132
133 #[must_use]
134 pub const fn source(&self) -> usize {
136 self.source
137 }
138
139 #[must_use]
140 pub const fn original_line(&self) -> usize {
142 self.original_line
143 }
144
145 #[must_use]
146 pub const fn original_column(&self) -> usize {
148 self.original_column
149 }
150}