1use crate::error::{Location, ParseResult};
10use crate::lexer::split_entity_name;
11use cranelift_codegen::ir::entities::{AnyEntity, DynamicType};
12use cranelift_codegen::ir::{
13 Block, Constant, DynamicStackSlot, FuncRef, GlobalValue, JumpTable, MemoryType, SigRef,
14 StackSlot, Value,
15};
16use std::collections::HashMap;
17
18#[derive(Debug, Default)]
20pub struct SourceMap {
21 locations: HashMap<AnyEntity, Location>,
23}
24
25impl SourceMap {
27 pub fn contains_value(&self, v: Value) -> bool {
29 self.locations.contains_key(&v.into())
30 }
31
32 pub fn contains_block(&self, block: Block) -> bool {
34 self.locations.contains_key(&block.into())
35 }
36
37 pub fn contains_ss(&self, ss: StackSlot) -> bool {
39 self.locations.contains_key(&ss.into())
40 }
41
42 pub fn contains_dss(&self, dss: DynamicStackSlot) -> bool {
44 self.locations.contains_key(&dss.into())
45 }
46
47 pub fn contains_gv(&self, gv: GlobalValue) -> bool {
49 self.locations.contains_key(&gv.into())
50 }
51
52 pub fn contains_sig(&self, sig: SigRef) -> bool {
54 self.locations.contains_key(&sig.into())
55 }
56
57 pub fn contains_fn(&self, fn_: FuncRef) -> bool {
59 self.locations.contains_key(&fn_.into())
60 }
61
62 pub fn contains_jt(&self, jt: JumpTable) -> bool {
64 self.locations.contains_key(&jt.into())
65 }
66
67 pub fn contains_constant(&self, c: Constant) -> bool {
69 self.locations.contains_key(&c.into())
70 }
71
72 pub fn lookup_str(&self, name: &str) -> Option<AnyEntity> {
75 split_entity_name(name).and_then(|(ent, num)| match ent {
76 "v" => Value::with_number(num).and_then(|v| {
77 if !self.contains_value(v) {
78 None
79 } else {
80 Some(v.into())
81 }
82 }),
83 "block" => Block::with_number(num).and_then(|block| {
84 if !self.contains_block(block) {
85 None
86 } else {
87 Some(block.into())
88 }
89 }),
90 "ss" => StackSlot::with_number(num).and_then(|ss| {
91 if !self.contains_ss(ss) {
92 None
93 } else {
94 Some(ss.into())
95 }
96 }),
97 "gv" => GlobalValue::with_number(num).and_then(|gv| {
98 if !self.contains_gv(gv) {
99 None
100 } else {
101 Some(gv.into())
102 }
103 }),
104 "sig" => SigRef::with_number(num).and_then(|sig| {
105 if !self.contains_sig(sig) {
106 None
107 } else {
108 Some(sig.into())
109 }
110 }),
111 "fn" => FuncRef::with_number(num).and_then(|fn_| {
112 if !self.contains_fn(fn_) {
113 None
114 } else {
115 Some(fn_.into())
116 }
117 }),
118 "jt" => JumpTable::with_number(num).and_then(|jt| {
119 if !self.contains_jt(jt) {
120 None
121 } else {
122 Some(jt.into())
123 }
124 }),
125 _ => None,
126 })
127 }
128
129 pub fn location(&self, entity: AnyEntity) -> Option<Location> {
131 self.locations.get(&entity).cloned()
132 }
133}
134
135impl SourceMap {
136 pub fn new() -> Self {
138 Self {
139 locations: HashMap::new(),
140 }
141 }
142
143 pub fn def_value(&mut self, entity: Value, loc: Location) -> ParseResult<()> {
145 self.def_entity(entity.into(), loc)
146 }
147
148 pub fn def_block(&mut self, entity: Block, loc: Location) -> ParseResult<()> {
150 self.def_entity(entity.into(), loc)
151 }
152
153 pub fn def_ss(&mut self, entity: StackSlot, loc: Location) -> ParseResult<()> {
155 self.def_entity(entity.into(), loc)
156 }
157
158 pub fn def_dss(&mut self, entity: DynamicStackSlot, loc: Location) -> ParseResult<()> {
160 self.def_entity(entity.into(), loc)
161 }
162
163 pub fn def_dt(&mut self, entity: DynamicType, loc: Location) -> ParseResult<()> {
165 self.def_entity(entity.into(), loc)
166 }
167
168 pub fn def_gv(&mut self, entity: GlobalValue, loc: Location) -> ParseResult<()> {
170 self.def_entity(entity.into(), loc)
171 }
172
173 pub fn def_mt(&mut self, entity: MemoryType, loc: Location) -> ParseResult<()> {
175 self.def_entity(entity.into(), loc)
176 }
177
178 pub fn def_sig(&mut self, entity: SigRef, loc: Location) -> ParseResult<()> {
180 self.def_entity(entity.into(), loc)
181 }
182
183 pub fn def_fn(&mut self, entity: FuncRef, loc: Location) -> ParseResult<()> {
185 self.def_entity(entity.into(), loc)
186 }
187
188 pub fn def_jt(&mut self, entity: JumpTable, loc: Location) -> ParseResult<()> {
190 self.def_entity(entity.into(), loc)
191 }
192
193 pub fn def_constant(&mut self, entity: Constant, loc: Location) -> ParseResult<()> {
195 self.def_entity(entity.into(), loc)
196 }
197
198 pub fn def_entity(&mut self, entity: AnyEntity, loc: Location) -> ParseResult<()> {
201 if self.locations.insert(entity, loc).is_some() {
202 err!(loc, "duplicate entity: {}", entity)
203 } else {
204 Ok(())
205 }
206 }
207}
208
209#[cfg(test)]
210mod tests {
211 use crate::{parse_test, ParseOptions};
212
213 #[test]
214 fn details() {
215 let tf = parse_test(
216 "function %detail() {
217 ss10 = explicit_slot 13
218 block0(v4: i32, v7: i32):
219 v10 = iadd v4, v7
220 }",
221 ParseOptions::default(),
222 )
223 .unwrap();
224 let map = &tf.functions[0].1.map;
225
226 assert_eq!(map.lookup_str("v0"), None);
227 assert_eq!(map.lookup_str("ss1"), None);
228 assert_eq!(map.lookup_str("ss10").unwrap().to_string(), "ss10");
229 assert_eq!(map.lookup_str("block0").unwrap().to_string(), "block0");
230 assert_eq!(map.lookup_str("v4").unwrap().to_string(), "v4");
231 assert_eq!(map.lookup_str("v7").unwrap().to_string(), "v7");
232 assert_eq!(map.lookup_str("v10").unwrap().to_string(), "v10");
233 }
234}