ion_binary_rs/
symbol_table.rs1use crate::binary_parser_types::SYSTEM_SYMBOL_TABLE;
2use log::trace;
3use std::collections::HashMap;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
8pub enum Symbol {
9 Symbol(String),
10 Dummy,
11}
12
13#[derive(Eq, PartialEq, Debug)]
14pub struct LocalSymbolTable(Vec<Symbol>);
15
16impl LocalSymbolTable {
17 pub fn new() -> LocalSymbolTable {
18 LocalSymbolTable(
19 SYSTEM_SYMBOL_TABLE
20 .to_vec()
21 .iter()
22 .map(|s| Symbol::Symbol(s.to_string()))
23 .collect(),
24 )
25 }
26
27 pub fn add_symbol(&mut self, symbol: Symbol) -> usize {
28 let id = self.0.len();
29 self.0.push(symbol);
30 id
31 }
32
33 pub fn add_symbols(&mut self, slice: &[Symbol]) {
34 for symbol in slice {
35 self.add_symbol(symbol.clone());
36 }
37 }
38
39 pub fn get_symbol_by_id(&self, id: usize) -> Option<&Symbol> {
40 self.0.get(id)
41 }
42
43 pub fn get_id_by_symbol(&self, symbol: &str) -> Option<usize> {
44 self.0
45 .iter()
46 .enumerate()
47 .find(|(_, value)| {
48 if let Symbol::Symbol(value) = value {
49 *value == symbol
50 } else {
51 false
52 }
53 })
54 .map(|value| value.0)
55 }
56
57 pub fn insert_dummy_symbols(&mut self, max_len: usize) {
58 for _ in 0..max_len {
59 self.add_symbol(Symbol::Dummy);
60 }
61 }
62
63 pub fn list_all_symbols(&self) -> &[Symbol] {
64 &self.0
65 }
66}
67
68#[derive(Debug)]
69pub struct SharedSymbolTable {
70 _name: String,
71 _version: u32,
72 symbols: Vec<Symbol>,
73}
74
75impl SharedSymbolTable {
76 pub fn is_superset(&self, table: &SharedSymbolTable) -> bool {
77 for (index, symbol) in table.symbols.iter().enumerate() {
78 match self.symbols.get(index) {
79 Some(value) if value == symbol => {}
80 _ => {
81 return false;
82 }
83 }
84 }
85
86 true
87 }
88
89 pub fn get_symbols_max_len(&self, max_len: usize) -> &[Symbol] {
90 if max_len > self.symbols.len() {
91 return &self.symbols;
92 }
93
94 self.symbols.split_at(max_len).0
95 }
96
97 pub fn get_all_symbols(&self) -> &[Symbol] {
98 &self.symbols
99 }
100}
101
102#[derive(Debug)]
103pub struct Import {
104 pub(crate) name: String,
105 pub(crate) version: Option<u32>,
106 pub(crate) max_len: Option<usize>,
107}
108
109#[derive(Eq, PartialEq, Debug)]
111pub enum SymbolContextError {
112 TableVersionAlreadyThere,
113 MaxIdNeededWhenImportingASharedTableWhereVersionIsNotAvailable,
114 MaxIdNeededWhenImportingANotFoundSharedTable,
115 InternalParserErrorThisIsABug,
116 NewTableIsNotSuperSetOfPrevious,
117}
118
119#[derive(Debug)]
120pub struct SymbolContext {
121 current_table: LocalSymbolTable,
122 shared_tables: HashMap<String, (u32, HashMap<u32, SharedSymbolTable>)>,
123}
124
125impl SymbolContext {
126 pub fn new() -> SymbolContext {
127 SymbolContext {
128 current_table: LocalSymbolTable::new(),
129 shared_tables: HashMap::new(),
130 }
131 }
132
133 pub fn set_new_table_from_current(&mut self, symbols: Vec<Symbol>) {
134 for symbol in symbols.into_iter() {
135 self.current_table.add_symbol(symbol);
136 }
137 }
138
139 pub fn add_shared_table(
140 &mut self,
141 name: String,
142 version: u32,
143 symbols: &[Symbol],
144 ) -> Result<(), SymbolContextError> {
145 let new_table = SharedSymbolTable {
146 _name: name.clone(),
147 _version: version,
148 symbols: symbols.to_vec(),
149 };
150
151 match self.shared_tables.get_mut(&name) {
152 Some(table_collection) => match table_collection.1.get_mut(&version) {
153 Some(_) => Err(SymbolContextError::TableVersionAlreadyThere),
154 None => {
155 SymbolContext::assert_new_table_is_superset(
156 &new_table,
157 &version,
158 &table_collection.1,
159 )?;
160
161 if table_collection.0 < version {
162 table_collection.0 = version;
163 }
164
165 trace!("New shared table imported {:?}", new_table);
166
167 table_collection.1.insert(version, new_table);
168 Ok(())
169 }
170 },
171 None => {
172 trace!("New shared table imported {:?}", new_table);
173
174 let mut new_hashmap = HashMap::new();
175 new_hashmap.insert(version, new_table);
176 let new_tuple = (version, new_hashmap);
177 self.shared_tables.insert(name, new_tuple);
178
179 Ok(())
180 }
181 }
182 }
183
184 pub fn assert_new_table_is_superset(
185 table: &SharedSymbolTable,
186 version: &u32,
187 tables: &HashMap<u32, SharedSymbolTable>,
188 ) -> Result<(), SymbolContextError> {
189 for index in (*version - 1)..=0 {
190 if let Some(existing_table) = tables.get(&index) {
191 if !table.is_superset(existing_table) {
192 return Err(SymbolContextError::NewTableIsNotSuperSetOfPrevious);
193 } else {
194 return Ok(());
195 }
196 }
197 }
198
199 Ok(())
200 }
201
202 pub fn set_new_table(
203 &mut self,
204 imports: &[Import],
205 symbols: &[Symbol],
206 ) -> Result<(), SymbolContextError> {
207 let mut new_table = LocalSymbolTable::new();
208
209 let symbols: Vec<Symbol> = symbols.to_vec();
210
211 for import in imports {
212 if import.name == "$ion" {
213 continue;
214 }
215
216 let version = if let Some(version) = import.version {
217 std::cmp::max(1, version)
218 } else {
219 1
220 };
221
222 match self.shared_tables.get(&import.name) {
223 Some(table_collection) => match table_collection.1.get(&version) {
224 Some(table) => {
225 let symbols = match import.max_len {
226 Some(len) => table.get_symbols_max_len(len),
227 None => table.get_all_symbols(),
228 };
229
230 new_table.add_symbols(symbols);
231 }
232 None => {
233 if let Some(max_len) = import.max_len {
234 let table = match table_collection.1.get(&table_collection.0) {
235 Some(table) => table,
236 None => {
237 return Err(SymbolContextError::InternalParserErrorThisIsABug)
238 }
239 };
240
241 let symbols = table.get_symbols_max_len(max_len);
242 new_table.add_symbols(symbols);
243 } else {
244 return Err(SymbolContextError::MaxIdNeededWhenImportingASharedTableWhereVersionIsNotAvailable);
245 }
246 }
247 },
248 None => {
249 if let Some(len) = import.max_len {
250 new_table.insert_dummy_symbols(len);
251 } else {
252 return Err(
253 SymbolContextError::MaxIdNeededWhenImportingANotFoundSharedTable,
254 );
255 }
256 }
257 }
258 }
259
260 new_table.add_symbols(&symbols);
261
262 trace!(
263 "New local table importing {:?} resulting in: {:?}",
264 imports,
265 new_table
266 );
267
268 self.current_table = new_table;
269
270 Ok(())
271 }
272
273 pub fn get_symbol_by_id(&self, id: usize) -> Option<&Symbol> {
274 self.current_table.get_symbol_by_id(id)
275 }
276
277 pub fn insert_symbol(&mut self, symbol: &str) -> usize {
278 match self.current_table.get_id_by_symbol(symbol) {
279 Some(id) => id,
280 None => self
281 .current_table
282 .add_symbol(Symbol::Symbol(symbol.to_string())),
283 }
284 }
285
286 pub fn dump_all_local_symbols(&self) -> Vec<String> {
287 self.current_table.list_all_symbols()[10..]
288 .iter()
289 .map(|s| match s {
290 Symbol::Symbol(name) => name.clone(),
291 _ => "".to_string(),
292 })
293 .collect()
294 }
295}
296
297impl Default for SymbolContext {
298 fn default() -> Self {
299 Self::new()
300 }
301}