(index<- ) ./libsyntax/codemap.rs
git branch: * master 5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
modified: Fri May 9 13:02:28 2014
1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 /*!
12
13 The CodeMap tracks all the source code used within a single crate, mapping
14 from integer byte positions to the original source code location. Each bit of
15 source parsed during crate parsing (typically files, in-memory strings, or
16 various bits of macro expansion) cover a continuous range of bytes in the
17 CodeMap and are represented by FileMaps. Byte positions are stored in `spans`
18 and used pervasively in the compiler. They are absolute positions within the
19 CodeMap, which upon request can be converted to line and column information,
20 source code snippets, etc.
21
22 */
23
24 use serialize::{Encodable, Decodable, Encoder, Decoder};
25 use std::cell::RefCell;
26 use std::rc::Rc;
27 use std::strbuf::StrBuf;
28
29 pub trait Pos {
30 fn from_uint(n: uint) -> Self;
31 fn to_uint(&self) -> uint;
32 }
33
34 /// A byte offset. Keep this small (currently 32-bits), as AST contains
35 /// a lot of them.
36 #[deriving(Clone, Eq, TotalEq, Hash, Ord, Show)]
37 pub struct BytePos(pub u32);
38
39 /// A character offset. Because of multibyte utf8 characters, a byte offset
40 /// is not equivalent to a character offset. The CodeMap will convert BytePos
41 /// values to CharPos values as necessary.
42 #[deriving(Eq, Hash, Ord, Show)]
43 pub struct CharPos(pub uint);
44
45 // FIXME: Lots of boilerplate in these impls, but so far my attempts to fix
46 // have been unsuccessful
47
48 impl Pos for BytePos {
49 fn from_uint(n: uint) -> BytePos { BytePos(n as u32) }
50 fn to_uint(&self) -> uint { let BytePos(n) = *self; n as uint }
51 }
52
53 impl Add<BytePos, BytePos> for BytePos {
54 fn add(&self, rhs: &BytePos) -> BytePos {
55 BytePos((self.to_uint() + rhs.to_uint()) as u32)
56 }
57 }
58
59 impl Sub<BytePos, BytePos> for BytePos {
60 fn sub(&self, rhs: &BytePos) -> BytePos {
61 BytePos((self.to_uint() - rhs.to_uint()) as u32)
62 }
63 }
64
65 impl Pos for CharPos {
66 fn from_uint(n: uint) -> CharPos { CharPos(n) }
67 fn to_uint(&self) -> uint { let CharPos(n) = *self; n }
68 }
69
70 impl Add<CharPos,CharPos> for CharPos {
71 fn add(&self, rhs: &CharPos) -> CharPos {
72 CharPos(self.to_uint() + rhs.to_uint())
73 }
74 }
75
76 impl Sub<CharPos,CharPos> for CharPos {
77 fn sub(&self, rhs: &CharPos) -> CharPos {
78 CharPos(self.to_uint() - rhs.to_uint())
79 }
80 }
81
82 /**
83 Spans represent a region of code, used for error reporting. Positions in spans
84 are *absolute* positions from the beginning of the codemap, not positions
85 relative to FileMaps. Methods on the CodeMap can be used to relate spans back
86 to the original source.
87 */
88 #[deriving(Clone, Show, Hash)]
89 pub struct Span {
90 pub lo: BytePos,
91 pub hi: BytePos,
92 /// Information about where the macro came from, if this piece of
93 /// code was created by a macro expansion.
94 pub expn_info: Option<@ExpnInfo>
95 }
96
97 pub static DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0), expn_info: None };
98
99 #[deriving(Clone, Eq, TotalEq, Encodable, Decodable, Hash)]
100 pub struct Spanned<T> {
101 pub node: T,
102 pub span: Span,
103 }
104
105 impl Eq for Span {
106 fn eq(&self, other: &Span) -> bool {
107 return (*self).lo == (*other).lo && (*self).hi == (*other).hi;
108 }
109 fn ne(&self, other: &Span) -> bool { !(*self).eq(other) }
110 }
111
112 impl TotalEq for Span {}
113
114 impl<S:Encoder<E>, E> Encodable<S, E> for Span {
115 /* Note #1972 -- spans are encoded but not decoded */
116 fn encode(&self, s: &mut S) -> Result<(), E> {
117 s.emit_nil()
118 }
119 }
120
121 impl<D:Decoder<E>, E> Decodable<D, E> for Span {
122 fn decode(_d: &mut D) -> Result<Span, E> {
123 Ok(DUMMY_SP)
124 }
125 }
126
127 pub fn spanned<T>(lo: BytePos, hi: BytePos, t: T) -> Spanned<T> {
128 respan(mk_sp(lo, hi), t)
129 }
130
131 pub fn respan<T>(sp: Span, t: T) -> Spanned<T> {
132 Spanned {node: t, span: sp}
133 }
134
135 pub fn dummy_spanned<T>(t: T) -> Spanned<T> {
136 respan(DUMMY_SP, t)
137 }
138
139 /* assuming that we're not in macro expansion */
140 pub fn mk_sp(lo: BytePos, hi: BytePos) -> Span {
141 Span {lo: lo, hi: hi, expn_info: None}
142 }
143
144 /// Return the span itself if it doesn't come from a macro expansion,
145 /// otherwise return the call site span up to the `enclosing_sp` by
146 /// following the `expn_info` chain.
147 pub fn original_sp(sp: Span, enclosing_sp: Span) -> Span {
148 match (sp.expn_info, enclosing_sp.expn_info) {
149 (None, _) => sp,
150 (Some(expn1), Some(expn2)) if expn1.call_site == expn2.call_site => sp,
151 (Some(expn1), _) => original_sp(expn1.call_site, enclosing_sp),
152 }
153 }
154
155 /// A source code location used for error reporting
156 pub struct Loc {
157 /// Information about the original source
158 pub file: Rc<FileMap>,
159 /// The (1-based) line number
160 pub line: uint,
161 /// The (0-based) column offset
162 pub col: CharPos
163 }
164
165 /// A source code location used as the result of lookup_char_pos_adj
166 // Actually, *none* of the clients use the filename *or* file field;
167 // perhaps they should just be removed.
168 pub struct LocWithOpt {
169 pub filename: FileName,
170 pub line: uint,
171 pub col: CharPos,
172 pub file: Option<Rc<FileMap>>,
173 }
174
175 // used to be structural records. Better names, anyone?
176 pub struct FileMapAndLine { pub fm: Rc<FileMap>, pub line: uint }
177 pub struct FileMapAndBytePos { pub fm: Rc<FileMap>, pub pos: BytePos }
178
179 /// The syntax with which a macro was invoked.
180 #[deriving(Clone, Hash, Show)]
181 pub enum MacroFormat {
182 /// e.g. #[deriving(...)] <item>
183 MacroAttribute,
184 /// e.g. `format!()`
185 MacroBang
186 }
187
188 #[deriving(Clone, Hash, Show)]
189 pub struct NameAndSpan {
190 /// The name of the macro that was invoked to create the thing
191 /// with this Span.
192 pub name: StrBuf,
193 /// The format with which the macro was invoked.
194 pub format: MacroFormat,
195 /// The span of the macro definition itself. The macro may not
196 /// have a sensible definition span (e.g. something defined
197 /// completely inside libsyntax) in which case this is None.
198 pub span: Option<Span>
199 }
200
201 /// Extra information for tracking macro expansion of spans
202 #[deriving(Hash, Show)]
203 pub struct ExpnInfo {
204 /// The location of the actual macro invocation, e.g. `let x =
205 /// foo!();`
206 ///
207 /// This may recursively refer to other macro invocations, e.g. if
208 /// `foo!()` invoked `bar!()` internally, and there was an
209 /// expression inside `bar!`; the call_site of the expression in
210 /// the expansion would point to the `bar!` invocation; that
211 /// call_site span would have its own ExpnInfo, with the call_site
212 /// pointing to the `foo!` invocation.
213 pub call_site: Span,
214 /// Information about the macro and its definition.
215 ///
216 /// The `callee` of the inner expression in the `call_site`
217 /// example would point to the `macro_rules! bar { ... }` and that
218 /// of the `bar!()` invocation would point to the `macro_rules!
219 /// foo { ... }`.
220 pub callee: NameAndSpan
221 }
222
223 pub type FileName = StrBuf;
224
225 pub struct FileLines {
226 pub file: Rc<FileMap>,
227 pub lines: Vec<uint>
228 }
229
230 /// Identifies an offset of a multi-byte character in a FileMap
231 pub struct MultiByteChar {
232 /// The absolute offset of the character in the CodeMap
233 pub pos: BytePos,
234 /// The number of bytes, >=2
235 pub bytes: uint,
236 }
237
238 /// A single source in the CodeMap
239 pub struct FileMap {
240 /// The name of the file that the source came from, source that doesn't
241 /// originate from files has names between angle brackets by convention,
242 /// e.g. `<anon>`
243 pub name: FileName,
244 /// The complete source code
245 pub src: StrBuf,
246 /// The start position of this source in the CodeMap
247 pub start_pos: BytePos,
248 /// Locations of lines beginnings in the source code
249 pub lines: RefCell<Vec<BytePos> >,
250 /// Locations of multi-byte characters in the source code
251 pub multibyte_chars: RefCell<Vec<MultiByteChar> >,
252 }
253
254 impl FileMap {
255 // EFFECT: register a start-of-line offset in the
256 // table of line-beginnings.
257 // UNCHECKED INVARIANT: these offsets must be added in the right
258 // order and must be in the right places; there is shared knowledge
259 // about what ends a line between this file and parse.rs
260 // WARNING: pos param here is the offset relative to start of CodeMap,
261 // and CodeMap will append a newline when adding a filemap without a newline at the end,
262 // so the safe way to call this is with value calculated as
263 // filemap.start_pos + newline_offset_relative_to_the_start_of_filemap.
264 pub fn next_line(&self, pos: BytePos) {
265 // the new charpos must be > the last one (or it's the first one).
266 let mut lines = self.lines.borrow_mut();;
267 let line_len = lines.len();
268 assert!(line_len == 0 || (*lines.get(line_len - 1) < pos))
269 lines.push(pos);
270 }
271
272 // get a line from the list of pre-computed line-beginnings
273 pub fn get_line(&self, line: int) -> StrBuf {
274 let mut lines = self.lines.borrow_mut();
275 let begin: BytePos = *lines.get(line as uint) - self.start_pos;
276 let begin = begin.to_uint();
277 let slice = self.src.as_slice().slice_from(begin);
278 match slice.find('\n') {
279 Some(e) => slice.slice_to(e).to_strbuf(),
280 None => slice.to_strbuf()
281 }
282 }
283
284 pub fn record_multibyte_char(&self, pos: BytePos, bytes: uint) {
285 assert!(bytes >=2 && bytes <= 4);
286 let mbc = MultiByteChar {
287 pos: pos,
288 bytes: bytes,
289 };
290 self.multibyte_chars.borrow_mut().push(mbc);
291 }
292
293 pub fn is_real_file(&self) -> bool {
294 !(self.name.as_slice().starts_with("<") &&
295 self.name.as_slice().ends_with(">"))
296 }
297 }
298
299 pub struct CodeMap {
300 pub files: RefCell<Vec<Rc<FileMap>>>
301 }
302
303 impl CodeMap {
304 pub fn new() -> CodeMap {
305 CodeMap {
306 files: RefCell::new(Vec::new()),
307 }
308 }
309
310 pub fn new_filemap(&self, filename: FileName, src: StrBuf) -> Rc<FileMap> {
311 let mut files = self.files.borrow_mut();
312 let start_pos = match files.last() {
313 None => 0,
314 Some(last) => last.start_pos.to_uint() + last.src.len(),
315 };
316
317 // Remove utf-8 BOM if any.
318 // FIXME #12884: no efficient/safe way to remove from the start of a string
319 // and reuse the allocation.
320 let mut src = if src.as_slice().starts_with("\ufeff") {
321 StrBuf::from_str(src.as_slice().slice_from(3))
322 } else {
323 StrBuf::from_str(src.as_slice())
324 };
325
326 // Append '\n' in case it's not already there.
327 // This is a workaround to prevent CodeMap.lookup_filemap_idx from accidentally
328 // overflowing into the next filemap in case the last byte of span is also the last
329 // byte of filemap, which leads to incorrect results from CodeMap.span_to_*.
330 if src.len() > 0 && !src.as_slice().ends_with("\n") {
331 src.push_char('\n');
332 }
333
334 let filemap = Rc::new(FileMap {
335 name: filename,
336 src: src.to_strbuf(),
337 start_pos: Pos::from_uint(start_pos),
338 lines: RefCell::new(Vec::new()),
339 multibyte_chars: RefCell::new(Vec::new()),
340 });
341
342 files.push(filemap.clone());
343
344 filemap
345 }
346
347 pub fn mk_substr_filename(&self, sp: Span) -> StrBuf {
348 let pos = self.lookup_char_pos(sp.lo);
349 (format!("<{}:{}:{}>",
350 pos.file.name,
351 pos.line,
352 pos.col.to_uint() + 1)).to_strbuf()
353 }
354
355 /// Lookup source information about a BytePos
356 pub fn lookup_char_pos(&self, pos: BytePos) -> Loc {
357 self.lookup_pos(pos)
358 }
359
360 pub fn lookup_char_pos_adj(&self, pos: BytePos) -> LocWithOpt {
361 let loc = self.lookup_char_pos(pos);
362 LocWithOpt {
363 filename: loc.file.name.to_strbuf(),
364 line: loc.line,
365 col: loc.col,
366 file: Some(loc.file)
367 }
368 }
369
370 pub fn span_to_str(&self, sp: Span) -> StrBuf {
371 if self.files.borrow().len() == 0 && sp == DUMMY_SP {
372 return "no-location".to_strbuf();
373 }
374
375 let lo = self.lookup_char_pos_adj(sp.lo);
376 let hi = self.lookup_char_pos_adj(sp.hi);
377 return (format!("{}:{}:{}: {}:{}",
378 lo.filename,
379 lo.line,
380 lo.col.to_uint() + 1,
381 hi.line,
382 hi.col.to_uint() + 1)).to_strbuf()
383 }
384
385 pub fn span_to_filename(&self, sp: Span) -> FileName {
386 self.lookup_char_pos(sp.lo).file.name.to_strbuf()
387 }
388
389 pub fn span_to_lines(&self, sp: Span) -> FileLines {
390 let lo = self.lookup_char_pos(sp.lo);
391 let hi = self.lookup_char_pos(sp.hi);
392 let mut lines = Vec::new();
393 for i in range(lo.line - 1u, hi.line as uint) {
394 lines.push(i);
395 };
396 FileLines {file: lo.file, lines: lines}
397 }
398
399 pub fn span_to_snippet(&self, sp: Span) -> Option<StrBuf> {
400 let begin = self.lookup_byte_offset(sp.lo);
401 let end = self.lookup_byte_offset(sp.hi);
402
403 // FIXME #8256: this used to be an assert but whatever precondition
404 // it's testing isn't true for all spans in the AST, so to allow the
405 // caller to not have to fail (and it can't catch it since the CodeMap
406 // isn't sendable), return None
407 if begin.fm.start_pos != end.fm.start_pos {
408 None
409 } else {
410 Some(begin.fm.src.as_slice().slice(begin.pos.to_uint(),
411 end.pos.to_uint()).to_strbuf())
412 }
413 }
414
415 pub fn get_filemap(&self, filename: &str) -> Rc<FileMap> {
416 for fm in self.files.borrow().iter() {
417 if filename == fm.name.as_slice() {
418 return fm.clone();
419 }
420 }
421 fail!("asking for {} which we don't know about", filename);
422 }
423
424 fn lookup_filemap_idx(&self, pos: BytePos) -> uint {
425 let files = self.files.borrow();
426 let files = files;
427 let len = files.len();
428 let mut a = 0u;
429 let mut b = len;
430 while b - a > 1u {
431 let m = (a + b) / 2u;
432 if files.get(m).start_pos > pos {
433 b = m;
434 } else {
435 a = m;
436 }
437 }
438 // There can be filemaps with length 0. These have the same start_pos as the previous
439 // filemap, but are not the filemaps we want (because they are length 0, they cannot
440 // contain what we are looking for). So, rewind until we find a useful filemap.
441 loop {
442 let lines = files.get(a).lines.borrow();
443 let lines = lines;
444 if lines.len() > 0 {
445 break;
446 }
447 if a == 0 {
448 fail!("position {} does not resolve to a source location", pos.to_uint());
449 }
450 a -= 1;
451 }
452 if a >= len {
453 fail!("position {} does not resolve to a source location", pos.to_uint())
454 }
455
456 return a;
457 }
458
459 fn lookup_line(&self, pos: BytePos) -> FileMapAndLine {
460 let idx = self.lookup_filemap_idx(pos);
461
462 let files = self.files.borrow();
463 let f = files.get(idx).clone();
464 let mut a = 0u;
465 {
466 let mut lines = f.lines.borrow_mut();
467 let mut b = lines.len();
468 while b - a > 1u {
469 let m = (a + b) / 2u;
470 if *lines.get(m) > pos { b = m; } else { a = m; }
471 }
472 }
473 FileMapAndLine {fm: f, line: a}
474 }
475
476 fn lookup_pos(&self, pos: BytePos) -> Loc {
477 let FileMapAndLine {fm: f, line: a} = self.lookup_line(pos);
478 let line = a + 1u; // Line numbers start at 1
479 let chpos = self.bytepos_to_file_charpos(pos);
480 let linebpos = *f.lines.borrow().get(a);
481 let linechpos = self.bytepos_to_file_charpos(linebpos);
482 debug!("codemap: byte pos {:?} is on the line at byte pos {:?}",
483 pos, linebpos);
484 debug!("codemap: char pos {:?} is on the line at char pos {:?}",
485 chpos, linechpos);
486 debug!("codemap: byte is on line: {:?}", line);
487 assert!(chpos >= linechpos);
488 Loc {
489 file: f,
490 line: line,
491 col: chpos - linechpos
492 }
493 }
494
495 fn lookup_byte_offset(&self, bpos: BytePos) -> FileMapAndBytePos {
496 let idx = self.lookup_filemap_idx(bpos);
497 let fm = self.files.borrow().get(idx).clone();
498 let offset = bpos - fm.start_pos;
499 FileMapAndBytePos {fm: fm, pos: offset}
500 }
501
502 // Converts an absolute BytePos to a CharPos relative to the filemap.
503 fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos {
504 debug!("codemap: converting {:?} to char pos", bpos);
505 let idx = self.lookup_filemap_idx(bpos);
506 let files = self.files.borrow();
507 let map = files.get(idx);
508
509 // The number of extra bytes due to multibyte chars in the FileMap
510 let mut total_extra_bytes = 0;
511
512 for mbc in map.multibyte_chars.borrow().iter() {
513 debug!("codemap: {:?}-byte char at {:?}", mbc.bytes, mbc.pos);
514 if mbc.pos < bpos {
515 // every character is at least one byte, so we only
516 // count the actual extra bytes.
517 total_extra_bytes += mbc.bytes - 1;
518 // We should never see a byte position in the middle of a
519 // character
520 assert!(bpos.to_uint() >= mbc.pos.to_uint() + mbc.bytes);
521 } else {
522 break;
523 }
524 }
525
526 assert!(map.start_pos.to_uint() + total_extra_bytes <= bpos.to_uint());
527 CharPos(bpos.to_uint() - map.start_pos.to_uint() - total_extra_bytes)
528 }
529 }
530
531 #[cfg(test)]
532 mod test {
533 use super::*;
534
535 #[test]
536 fn t1 () {
537 let cm = CodeMap::new();
538 let fm = cm.new_filemap("blork.rs".to_strbuf(),
539 "first line.\nsecond line".to_strbuf());
540 fm.next_line(BytePos(0));
541 assert_eq!(&fm.get_line(0),&"first line.".to_strbuf());
542 // TESTING BROKEN BEHAVIOR:
543 fm.next_line(BytePos(10));
544 assert_eq!(&fm.get_line(1), &".".to_strbuf());
545 }
546
547 #[test]
548 #[should_fail]
549 fn t2 () {
550 let cm = CodeMap::new();
551 let fm = cm.new_filemap("blork.rs".to_strbuf(),
552 "first line.\nsecond line".to_strbuf());
553 // TESTING *REALLY* BROKEN BEHAVIOR:
554 fm.next_line(BytePos(0));
555 fm.next_line(BytePos(10));
556 fm.next_line(BytePos(2));
557 }
558
559 fn init_code_map() -> CodeMap {
560 let cm = CodeMap::new();
561 let fm1 = cm.new_filemap("blork.rs".to_strbuf(),
562 "first line.\nsecond line".to_strbuf());
563 let fm2 = cm.new_filemap("empty.rs".to_strbuf(),
564 "".to_strbuf());
565 let fm3 = cm.new_filemap("blork2.rs".to_strbuf(),
566 "first line.\nsecond line".to_strbuf());
567
568 fm1.next_line(BytePos(0));
569 fm1.next_line(BytePos(12));
570 fm2.next_line(BytePos(24));
571 fm3.next_line(BytePos(24));
572 fm3.next_line(BytePos(34));
573
574 cm
575 }
576
577 #[test]
578 fn t3() {
579 // Test lookup_byte_offset
580 let cm = init_code_map();
581
582 let fmabp1 = cm.lookup_byte_offset(BytePos(22));
583 assert_eq!(fmabp1.fm.name, "blork.rs".to_strbuf());
584 assert_eq!(fmabp1.pos, BytePos(22));
585
586 let fmabp2 = cm.lookup_byte_offset(BytePos(24));
587 assert_eq!(fmabp2.fm.name, "blork2.rs".to_strbuf());
588 assert_eq!(fmabp2.pos, BytePos(0));
589 }
590
591 #[test]
592 fn t4() {
593 // Test bytepos_to_file_charpos
594 let cm = init_code_map();
595
596 let cp1 = cm.bytepos_to_file_charpos(BytePos(22));
597 assert_eq!(cp1, CharPos(22));
598
599 let cp2 = cm.bytepos_to_file_charpos(BytePos(24));
600 assert_eq!(cp2, CharPos(0));
601 }
602
603 #[test]
604 fn t5() {
605 // Test zero-length filemaps.
606 let cm = init_code_map();
607
608 let loc1 = cm.lookup_char_pos(BytePos(22));
609 assert_eq!(loc1.file.name, "blork.rs".to_strbuf());
610 assert_eq!(loc1.line, 2);
611 assert_eq!(loc1.col, CharPos(10));
612
613 let loc2 = cm.lookup_char_pos(BytePos(24));
614 assert_eq!(loc2.file.name, "blork2.rs".to_strbuf());
615 assert_eq!(loc2.line, 1);
616 assert_eq!(loc2.col, CharPos(0));
617 }
618
619 fn init_code_map_mbc() -> CodeMap {
620 let cm = CodeMap::new();
621 // ⬠is a three byte utf8 char.
622 let fm1 =
623 cm.new_filemap("blork.rs".to_strbuf(),
624 "firâ¬st â¬â¬â¬â¬ line.\nsecond line".to_strbuf());
625 let fm2 = cm.new_filemap("blork2.rs".to_strbuf(),
626 "first lineâ¬â¬.\n⬠second line".to_strbuf());
627
628 fm1.next_line(BytePos(0));
629 fm1.next_line(BytePos(22));
630 fm2.next_line(BytePos(40));
631 fm2.next_line(BytePos(58));
632
633 fm1.record_multibyte_char(BytePos(3), 3);
634 fm1.record_multibyte_char(BytePos(9), 3);
635 fm1.record_multibyte_char(BytePos(12), 3);
636 fm1.record_multibyte_char(BytePos(15), 3);
637 fm1.record_multibyte_char(BytePos(18), 3);
638 fm2.record_multibyte_char(BytePos(50), 3);
639 fm2.record_multibyte_char(BytePos(53), 3);
640 fm2.record_multibyte_char(BytePos(58), 3);
641
642 cm
643 }
644
645 #[test]
646 fn t6() {
647 // Test bytepos_to_file_charpos in the presence of multi-byte chars
648 let cm = init_code_map_mbc();
649
650 let cp1 = cm.bytepos_to_file_charpos(BytePos(3));
651 assert_eq!(cp1, CharPos(3));
652
653 let cp2 = cm.bytepos_to_file_charpos(BytePos(6));
654 assert_eq!(cp2, CharPos(4));
655
656 let cp3 = cm.bytepos_to_file_charpos(BytePos(56));
657 assert_eq!(cp3, CharPos(12));
658
659 let cp4 = cm.bytepos_to_file_charpos(BytePos(61));
660 assert_eq!(cp4, CharPos(15));
661 }
662
663 #[test]
664 fn t7() {
665 // Test span_to_lines for a span ending at the end of filemap
666 let cm = init_code_map();
667 let span = Span {lo: BytePos(12), hi: BytePos(23), expn_info: None};
668 let file_lines = cm.span_to_lines(span);
669
670 assert_eq!(file_lines.file.name, "blork.rs".to_strbuf());
671 assert_eq!(file_lines.lines.len(), 1);
672 assert_eq!(*file_lines.lines.get(0), 1u);
673 }
674
675 #[test]
676 fn t8() {
677 // Test span_to_snippet for a span ending at the end of filemap
678 let cm = init_code_map();
679 let span = Span {lo: BytePos(12), hi: BytePos(23), expn_info: None};
680 let snippet = cm.span_to_snippet(span);
681
682 assert_eq!(snippet, Some("second line".to_strbuf()));
683 }
684
685 #[test]
686 fn t9() {
687 // Test span_to_str for a span ending at the end of filemap
688 let cm = init_code_map();
689 let span = Span {lo: BytePos(12), hi: BytePos(23), expn_info: None};
690 let sstr = cm.span_to_str(span);
691
692 assert_eq!(sstr, "blork.rs:2:1: 2:12".to_strbuf());
693 }
694 }
libsyntax/codemap.rs:238:35-238:35 -struct- definition:
/// A single source in the CodeMap
pub struct FileMap {
/// The name of the file that the source came from, source that doesn't
references:- 17334: let filemap = Rc::new(FileMap {
335: name: filename,
--
415: pub fn get_filemap(&self, filename: &str) -> Rc<FileMap> {
416: for fm in self.files.borrow().iter() {
libsyntax/parse/mod.rs:
238: pub fn string_to_filemap(sess: &ParseSess, source: StrBuf, path: StrBuf)
239: -> Rc<FileMap> {
240: sess.span_diagnostic.cm.new_filemap(path, source)
--
243: // given a filemap, produce a sequence of token-trees
244: pub fn filemap_to_tts(sess: &ParseSess, filemap: Rc<FileMap>)
245: -> Vec<ast::TokenTree> {
libsyntax/parse/lexer.rs:
51: pub curr: Option<char>,
52: pub filemap: Rc<codemap::FileMap>,
53: /* cached: */
--
73: pub fn new_low_level_string_reader<'a>(span_diagnostic: &'a SpanHandler,
74: filemap: Rc<codemap::FileMap>)
75: -> StringReader<'a> {
libsyntax/codemap.rs:
157: /// Information about the original source
158: pub file: Rc<FileMap>,
159: /// The (1-based) line number
libsyntax/codemap.rs:28:1-28:1 -trait- definition:
pub trait Pos {
fn from_uint(n: uint) -> Self;
fn to_uint(&self) -> uint;
references:- 329: pub trait Pos {
30: fn from_uint(n: uint) -> Self;
31: fn to_uint(&self) -> uint;
--
48: impl Pos for BytePos {
49: fn from_uint(n: uint) -> BytePos { BytePos(n as u32) }
--
65: impl Pos for CharPos {
66: fn from_uint(n: uint) -> CharPos { CharPos(n) }
libsyntax/codemap.rs:188:31-188:31 -struct- definition:
pub struct NameAndSpan {
/// The name of the macro that was invoked to create the thing
/// with this Span.
references:- 17189: pub struct NameAndSpan {
libsyntax/ext/expand.rs:
271: call_site: attr.span,
272: callee: NameAndSpan {
273: name: mname.get().to_strbuf(),
--
335: call_site: attr.span,
336: callee: NameAndSpan {
337: name: mname.get().to_strbuf(),
--
579: call_site: s.span,
580: callee: NameAndSpan {
581: name: extnamestr.get().to_strbuf(),
libsyntax/ext/deriving/generic.rs:
988: call_site: to_set,
989: callee: codemap::NameAndSpan {
990: name: format!("deriving({})", trait_name).to_strbuf(),
libsyntax/codemap.rs:
189: pub struct NameAndSpan {
libsyntax/ext/source_util.rs:
160: ExpnInfo {
161: callee: NameAndSpan { name: ref name, .. },
162: ..
libsyntax/codemap.rs:
219: /// foo { ... }`.
220: pub callee: NameAndSpan
221: }
libsyntax/codemap.rs:298:1-298:1 -struct- definition:
pub struct CodeMap {
pub files: RefCell<Vec<Rc<FileMap>>>
}
references:- 18304: pub fn new() -> CodeMap {
305: CodeMap {
306: files: RefCell::new(Vec::new()),
libsyntax/print/pprust.rs:
96: // copy forward.
97: pub fn print_crate<'a>(cm: &'a CodeMap,
98: span_diagnostic: &diagnostic::SpanHandler,
libsyntax/ext/base.rs:
413: pub fn codemap(&self) -> &'a CodeMap { &self.parse_sess.span_diagnostic.cm }
414: pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess }
libsyntax/diagnostic.rs:
312: fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, rsp: RenderSpan,
313: msg: &str, lvl: Level, custom: bool) -> io::IoResult<()> {
--
450: fn print_macro_backtrace(w: &mut EmitterWriter,
451: cm: &codemap::CodeMap,
452: sp: Span)
libsyntax/print/pprust.rs:
58: pub s: pp::Printer,
59: cm: Option<&'a CodeMap>,
60: intr: Rc<token::IdentInterner>,
libsyntax/codemap.rs:222:1-222:1 -NK_AS_STR_TODO- definition:
pub type FileName = StrBuf;
pub struct FileLines {
pub file: Rc<FileMap>,
references:- 4242: /// e.g. `<anon>`
243: pub name: FileName,
244: /// The complete source code
--
310: pub fn new_filemap(&self, filename: FileName, src: StrBuf) -> Rc<FileMap> {
311: let mut files = self.files.borrow_mut();
--
385: pub fn span_to_filename(&self, sp: Span) -> FileName {
386: self.lookup_char_pos(sp.lo).file.name.to_strbuf()
libsyntax/codemap.rs:180:31-180:31 -enum- definition:
pub enum MacroFormat {
/// e.g. #[deriving(...)] <item>
MacroAttribute,
references:- 5179: /// The syntax with which a macro was invoked.
181: pub enum MacroFormat {
--
193: /// The format with which the macro was invoked.
194: pub format: MacroFormat,
195: /// The span of the macro definition itself. The macro may not
libsyntax/codemap.rs:139:49-139:49 -fn- definition:
/* assuming that we're not in macro expansion */
pub fn mk_sp(lo: BytePos, hi: BytePos) -> Span {
Span {lo: lo, hi: hi, expn_info: None}
references:- 52libsyntax/parse/lexer.rs:
libsyntax/parse/parser.rs:
libsyntax/parse/attr.rs:
libsyntax/ext/tt/macro_parser.rs:
libsyntax/parse/parser.rs:
libsyntax/codemap.rs:42:33-42:33 -struct- definition:
pub struct CharPos(pub uint);
// FIXME: Lots of boilerplate in these impls, but so far my attempts to fix
// have been unsuccessful
references:- 2841: /// values to CharPos values as necessary.
43: pub struct CharPos(pub uint);
--
70: impl Add<CharPos,CharPos> for CharPos {
71: fn add(&self, rhs: &CharPos) -> CharPos {
--
76: impl Sub<CharPos,CharPos> for CharPos {
77: fn sub(&self, rhs: &CharPos) -> CharPos {
78: CharPos(self.to_uint() - rhs.to_uint())
--
502: // Converts an absolute BytePos to a CharPos relative to the filemap.
503: fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos {
504: debug!("codemap: converting {:?} to char pos", bpos);
libsyntax/parse/lexer.rs:
48: // The column of the next character to read
49: pub col: CharPos,
50: // The last character to be read
libsyntax/parse/comments.rs:
244: fn trim_whitespace_prefix_and_push_line(lines: &mut Vec<StrBuf> ,
245: s: StrBuf, col: CharPos) {
246: let len = s.len();
libsyntax/codemap.rs:
65: impl Pos for CharPos {
66: fn from_uint(n: uint) -> CharPos { CharPos(n) }
libsyntax/codemap.rs:126:1-126:1 -fn- definition:
pub fn spanned<T>(lo: BytePos, hi: BytePos, t: T) -> Spanned<T> {
respan(mk_sp(lo, hi), t)
}
references:- 33libsyntax/parse/parser.rs:
libsyntax/parse/attr.rs:
libsyntax/attr.rs:
libsyntax/parse/parser.rs:
libsyntax/codemap.rs:224:1-224:1 -struct- definition:
pub struct FileLines {
pub file: Rc<FileMap>,
pub lines: Vec<uint>
references:- 4395: };
396: FileLines {file: lo.file, lines: lines}
397: }
libsyntax/diagnostic.rs:
416: lvl: Level,
417: lines: codemap::FileLines)
418: -> io::IoResult<()> {
libsyntax/codemap.rs:
389: pub fn span_to_lines(&self, sp: Span) -> FileLines {
390: let lo = self.lookup_char_pos(sp.lo);
libsyntax/codemap.rs:88:31-88:31 -struct- definition:
pub struct Span {
pub lo: BytePos,
pub hi: BytePos,
references:- 452libsyntax/parse/parser.rs:
libsyntax/ext/base.rs:
libsyntax/ext/expand.rs:
libsyntax/codemap.rs:
libsyntax/ast.rs:
libsyntax/diagnostic.rs:
libsyntax/ast.rs:
libsyntax/ast_util.rs:
libsyntax/ast_map.rs:
libsyntax/visit.rs:
libsyntax/fold.rs:
libsyntax/parse/mod.rs:
libsyntax/parse/lexer.rs:
libsyntax/parse/parser.rs:
libsyntax/parse/obsolete.rs:
libsyntax/print/pprust.rs:
libsyntax/ext/asm.rs:
libsyntax/ext/base.rs:
libsyntax/ext/expand.rs:
libsyntax/ext/registrar.rs:
libsyntax/ext/quote.rs:
libsyntax/ext/deriving/mod.rs:
libsyntax/ext/deriving/bounds.rs:
libsyntax/ext/deriving/clone.rs:
libsyntax/ext/deriving/encodable.rs:
libsyntax/ext/deriving/decodable.rs:
libsyntax/ext/deriving/hash.rs:
libsyntax/ext/deriving/rand.rs:
libsyntax/ext/deriving/show.rs:
libsyntax/ext/deriving/zero.rs:
libsyntax/ext/deriving/default.rs:
libsyntax/ext/deriving/primitive.rs:
libsyntax/ext/deriving/cmp/eq.rs:
libsyntax/ext/deriving/cmp/totaleq.rs:
libsyntax/ext/deriving/cmp/ord.rs:
libsyntax/ext/deriving/cmp/totalord.rs:
libsyntax/ext/deriving/generic.rs:
libsyntax/ext/deriving/ty.rs:
libsyntax/ext/build.rs:
libsyntax/ext/tt/transcribe.rs:
libsyntax/ext/tt/macro_parser.rs:
libsyntax/ext/tt/macro_rules.rs:
libsyntax/ext/cfg.rs:
libsyntax/ext/fmt.rs:
libsyntax/ext/format.rs:
libsyntax/ext/env.rs:
libsyntax/ext/bytes.rs:
libsyntax/ext/concat.rs:
libsyntax/ext/concat_idents.rs:
libsyntax/ext/log_syntax.rs:
libsyntax/ext/source_util.rs:
libsyntax/ext/trace_macros.rs:
libsyntax/attr.rs:
libsyntax/diagnostic.rs:
libsyntax/ext/deriving/generic.rs:
libsyntax/codemap.rs:176:66-176:66 -struct- definition:
pub struct FileMapAndLine { pub fm: Rc<FileMap>, pub line: uint }
pub struct FileMapAndBytePos { pub fm: Rc<FileMap>, pub pos: BytePos }
/// The syntax with which a macro was invoked.
references:- 2495: fn lookup_byte_offset(&self, bpos: BytePos) -> FileMapAndBytePos {
496: let idx = self.lookup_filemap_idx(bpos);
--
498: let offset = bpos - fm.start_pos;
499: FileMapAndBytePos {fm: fm, pos: offset}
500: }
libsyntax/codemap.rs:230:64-230:64 -struct- definition:
/// Identifies an offset of a multi-byte character in a FileMap
pub struct MultiByteChar {
/// The absolute offset of the character in the CodeMap
references:- 2250: /// Locations of multi-byte characters in the source code
251: pub multibyte_chars: RefCell<Vec<MultiByteChar> >,
252: }
--
285: assert!(bytes >=2 && bytes <= 4);
286: let mbc = MultiByteChar {
287: pos: pos,
libsyntax/codemap.rs:99:60-99:60 -struct- definition:
pub struct Spanned<T> {
pub node: T,
pub span: Span,
references:- 72libsyntax/fold.rs:
libsyntax/parse/parser.rs:
libsyntax/parse/attr.rs:
libsyntax/ext/expand.rs:
libsyntax/ext/build.rs:
libsyntax/ext/tt/macro_rules.rs:
libsyntax/codemap.rs:
libsyntax/attr.rs:
libsyntax/ast.rs:
libsyntax/parse/parser.rs:
libsyntax/print/pprust.rs:
libsyntax/ext/expand.rs:
libsyntax/ext/tt/macro_parser.rs:
libsyntax/ast.rs:
libsyntax/codemap.rs:202:24-202:24 -struct- definition:
pub struct ExpnInfo {
/// The location of the actual macro invocation, e.g. `let x =
/// foo!();`
references:- 22libsyntax/ext/expand.rs:
269: Some(&ItemDecorator(dec_fn)) => {
270: fld.cx.bt_push(ExpnInfo {
271: call_site: attr.span,
--
333: Some(&ItemModifier(dec_fn)) => {
334: fld.cx.bt_push(ExpnInfo {
335: call_site: attr.span,
--
411: }
412: fld.cx.bt_push(ExpnInfo {
413: call_site: it.span,
--
577: Some(&NormalTT(ref expandfun, exp_span)) => {
578: fld.cx.bt_push(ExpnInfo {
579: call_site: s.span,
libsyntax/ext/deriving/generic.rs:
986: };
987: to_set.expn_info = Some(@codemap::ExpnInfo {
988: call_site: to_set,
libsyntax/codemap.rs:
201: /// Extra information for tracking macro expansion of spans
203: pub struct ExpnInfo {
libsyntax/ext/base.rs:
433: match ei {
434: ExpnInfo {call_site: cs, callee: ref callee} => {
435: self.backtrace =
libsyntax/ext/expand.rs:
944: fn original_span(cx: &ExtCtxt) -> @codemap::ExpnInfo {
945: let mut relevant_info = cx.backtrace();
libsyntax/ext/source_util.rs:
155: match *expn_info {
156: ExpnInfo { call_site: ref call_site, .. } => {
157: match call_site.expn_info {
--
159: match *next_expn_info {
160: ExpnInfo {
161: callee: NameAndSpan { name: ref name, .. },
libsyntax/ext/base.rs:
435: self.backtrace =
436: Some(@ExpnInfo {
437: call_site: Span {lo: cs.lo, hi: cs.hi,
libsyntax/codemap.rs:36:49-36:49 -struct- definition:
pub struct BytePos(pub u32);
/// A character offset. Because of multibyte utf8 characters, a byte offset
/// is not equivalent to a character offset. The CodeMap will convert BytePos
references:- 85libsyntax/parse/lexer.rs:
libsyntax/parse/parser.rs:
libsyntax/parse/comments.rs:
libsyntax/print/pprust.rs:
libsyntax/ext/tt/macro_parser.rs:
libsyntax/attr.rs:
libsyntax/codemap.rs:
libsyntax/codemap.rs:167:40-167:40 -struct- definition:
// perhaps they should just be removed.
pub struct LocWithOpt {
pub filename: FileName,
references:- 2361: let loc = self.lookup_char_pos(pos);
362: LocWithOpt {
363: filename: loc.file.name.to_strbuf(),
libsyntax/codemap.rs:134:1-134:1 -fn- definition:
pub fn dummy_spanned<T>(t: T) -> Spanned<T> {
respan(DUMMY_SP, t)
}
references:- 18libsyntax/ext/quote.rs:
194: fn to_source(&self) -> StrBuf {
195: let lit = dummy_spanned(ast::LitUint(*self as u64, ast::TyU));
196: pprust::lit_to_str(&lit)
--
208: fn to_source(&self) -> StrBuf {
209: let lit = dummy_spanned(ast::LitUint(*self as u64, ast::TyU16));
210: pprust::lit_to_str(&lit)
--
215: fn to_source(&self) -> StrBuf {
216: let lit = dummy_spanned(ast::LitUint(*self as u64, ast::TyU32));
217: pprust::lit_to_str(&lit)
libsyntax/attr.rs:
153: pub fn mk_word_item(name: InternedString) -> @MetaItem {
154: @dummy_spanned(MetaWord(name))
155: }
--
157: pub fn mk_attr(item: @MetaItem) -> Attribute {
158: dummy_spanned(Attribute_ {
159: style: ast::AttrInner,
libsyntax/ext/quote.rs:
222: fn to_source(&self) -> StrBuf {
223: let lit = dummy_spanned(ast::LitUint(*self as u64, ast::TyU64));
224: pprust::lit_to_str(&lit)
libsyntax/codemap.rs:130:1-130:1 -fn- definition:
pub fn respan<T>(sp: Span, t: T) -> Spanned<T> {
Spanned {node: t, span: sp}
}
references:- 34libsyntax/fold.rs:
libsyntax/parse/obsolete.rs:
libsyntax/ext/base.rs:
libsyntax/ext/deriving/generic.rs:
libsyntax/ext/deriving/ty.rs:
libsyntax/ext/build.rs:
libsyntax/ext/format.rs:
libsyntax/ext/build.rs:
libsyntax/codemap.rs:175:56-175:56 -struct- definition:
// used to be structural records. Better names, anyone?
pub struct FileMapAndLine { pub fm: Rc<FileMap>, pub line: uint }
pub struct FileMapAndBytePos { pub fm: Rc<FileMap>, pub pos: BytePos }
references:- 3476: fn lookup_pos(&self, pos: BytePos) -> Loc {
477: let FileMapAndLine {fm: f, line: a} = self.lookup_line(pos);
478: let line = a + 1u; // Line numbers start at 1
libsyntax/codemap.rs:155:52-155:52 -struct- definition:
/// A source code location used for error reporting
pub struct Loc {
/// Information about the original source
references:- 3487: assert!(chpos >= linechpos);
488: Loc {
489: file: f,