//! Source map associating entities with their source locations. //! //! When the parser reads in a source file, it records the locations of the //! definitions of entities like instructions, EBBs, and values. //! //! The `SourceMap` struct defined in this module makes this mapping available //! to parser clients. use cranelift_codegen::ir::entities::AnyEntity; use cranelift_codegen::ir::{ Ebb, FuncRef, GlobalValue, Heap, JumpTable, SigRef, StackSlot, Table, Value, }; use error::{Location, ParseResult}; use lexer::split_entity_name; use std::collections::HashMap; /// Mapping from entity names to source locations. #[derive(Debug, Default)] pub struct SourceMap { // Store locations for entities, including instructions. locations: HashMap, } /// Read-only interface which is exposed outside the parser crate. impl SourceMap { /// Look up a value entity. pub fn contains_value(&self, v: Value) -> bool { self.locations.contains_key(&v.into()) } /// Look up a EBB entity. pub fn contains_ebb(&self, ebb: Ebb) -> bool { self.locations.contains_key(&ebb.into()) } /// Look up a stack slot entity. pub fn contains_ss(&self, ss: StackSlot) -> bool { self.locations.contains_key(&ss.into()) } /// Look up a global value entity. pub fn contains_gv(&self, gv: GlobalValue) -> bool { self.locations.contains_key(&gv.into()) } /// Look up a heap entity. pub fn contains_heap(&self, heap: Heap) -> bool { self.locations.contains_key(&heap.into()) } /// Look up a table entity. pub fn contains_table(&self, table: Table) -> bool { self.locations.contains_key(&table.into()) } /// Look up a signature entity. pub fn contains_sig(&self, sig: SigRef) -> bool { self.locations.contains_key(&sig.into()) } /// Look up a function entity. pub fn contains_fn(&self, fn_: FuncRef) -> bool { self.locations.contains_key(&fn_.into()) } /// Look up a jump table entity. pub fn contains_jt(&self, jt: JumpTable) -> bool { self.locations.contains_key(&jt.into()) } /// Look up an entity by source name. /// Returns the entity reference corresponding to `name`, if it exists. pub fn lookup_str(&self, name: &str) -> Option { split_entity_name(name).and_then(|(ent, num)| match ent { "v" => Value::with_number(num).and_then(|v| { if !self.contains_value(v) { None } else { Some(v.into()) } }), "ebb" => Ebb::with_number(num).and_then(|ebb| { if !self.contains_ebb(ebb) { None } else { Some(ebb.into()) } }), "ss" => StackSlot::with_number(num).and_then(|ss| { if !self.contains_ss(ss) { None } else { Some(ss.into()) } }), "gv" => GlobalValue::with_number(num).and_then(|gv| { if !self.contains_gv(gv) { None } else { Some(gv.into()) } }), "heap" => Heap::with_number(num).and_then(|heap| { if !self.contains_heap(heap) { None } else { Some(heap.into()) } }), "table" => Table::with_number(num).and_then(|table| { if !self.contains_table(table) { None } else { Some(table.into()) } }), "sig" => SigRef::with_number(num).and_then(|sig| { if !self.contains_sig(sig) { None } else { Some(sig.into()) } }), "fn" => FuncRef::with_number(num).and_then(|fn_| { if !self.contains_fn(fn_) { None } else { Some(fn_.into()) } }), "jt" => JumpTable::with_number(num).and_then(|jt| { if !self.contains_jt(jt) { None } else { Some(jt.into()) } }), _ => None, }) } /// Get the source location where an entity was defined. pub fn location(&self, entity: AnyEntity) -> Option { self.locations.get(&entity).cloned() } } impl SourceMap { /// Create a new empty `SourceMap`. pub fn new() -> Self { Self { locations: HashMap::new(), } } /// Define the value `entity`. pub fn def_value(&mut self, entity: Value, loc: Location) -> ParseResult<()> { self.def_entity(entity.into(), loc) } /// Define the ebb `entity`. pub fn def_ebb(&mut self, entity: Ebb, loc: Location) -> ParseResult<()> { self.def_entity(entity.into(), loc) } /// Define the stack slot `entity`. pub fn def_ss(&mut self, entity: StackSlot, loc: Location) -> ParseResult<()> { self.def_entity(entity.into(), loc) } /// Define the global value `entity`. pub fn def_gv(&mut self, entity: GlobalValue, loc: Location) -> ParseResult<()> { self.def_entity(entity.into(), loc) } /// Define the heap `entity`. pub fn def_heap(&mut self, entity: Heap, loc: Location) -> ParseResult<()> { self.def_entity(entity.into(), loc) } /// Define the table `entity`. pub fn def_table(&mut self, entity: Table, loc: Location) -> ParseResult<()> { self.def_entity(entity.into(), loc) } /// Define the signature `entity`. pub fn def_sig(&mut self, entity: SigRef, loc: Location) -> ParseResult<()> { self.def_entity(entity.into(), loc) } /// Define the external function `entity`. pub fn def_fn(&mut self, entity: FuncRef, loc: Location) -> ParseResult<()> { self.def_entity(entity.into(), loc) } /// Define the jump table `entity`. pub fn def_jt(&mut self, entity: JumpTable, loc: Location) -> ParseResult<()> { self.def_entity(entity.into(), loc) } /// Define an entity. This can be used for instructions whose numbers never /// appear in source, or implicitly defined signatures. pub fn def_entity(&mut self, entity: AnyEntity, loc: Location) -> ParseResult<()> { if self.locations.insert(entity, loc).is_some() { err!(loc, "duplicate entity: {}", entity) } else { Ok(()) } } } #[cfg(test)] mod tests { use parse_test; #[test] fn details() { let tf = parse_test( "function %detail() { ss10 = incoming_arg 13 jt10 = jump_table ebb0 ebb0(v4: i32, v7: i32): v10 = iadd v4, v7 }", None, None, ).unwrap(); let map = &tf.functions[0].1.map; assert_eq!(map.lookup_str("v0"), None); assert_eq!(map.lookup_str("ss1"), None); assert_eq!(map.lookup_str("ss10").unwrap().to_string(), "ss10"); assert_eq!(map.lookup_str("jt10").unwrap().to_string(), "jt10"); assert_eq!(map.lookup_str("ebb0").unwrap().to_string(), "ebb0"); assert_eq!(map.lookup_str("v4").unwrap().to_string(), "v4"); assert_eq!(map.lookup_str("v7").unwrap().to_string(), "v7"); assert_eq!(map.lookup_str("v10").unwrap().to_string(), "v10"); } }