2011-12-13 18:25:51 -06:00
|
|
|
import core::{vec, uint, str, option, result};
|
|
|
|
import option::{some, none};
|
2011-07-05 04:48:19 -05:00
|
|
|
|
2011-09-02 17:34:58 -05:00
|
|
|
type filename = str;
|
2011-07-05 04:48:19 -05:00
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
type file_pos = {ch: uint, byte: uint};
|
2011-07-16 01:01:10 -05:00
|
|
|
|
2011-07-05 04:48:19 -05:00
|
|
|
/* A codemap is a thing that maps uints to file/line/column positions
|
|
|
|
* in a crate. This to make it possible to represent the positions
|
|
|
|
* with single-word things, rather than passing records all over the
|
|
|
|
* compiler.
|
|
|
|
*/
|
2011-07-27 07:19:39 -05:00
|
|
|
type filemap =
|
2012-01-25 16:53:45 -06:00
|
|
|
@{name: filename, src: @str,
|
|
|
|
start_pos: file_pos, mutable lines: [file_pos]};
|
2011-07-05 04:48:19 -05:00
|
|
|
|
2011-08-04 18:20:09 -05:00
|
|
|
type codemap = @{mutable files: [filemap]};
|
2011-07-05 04:48:19 -05:00
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
type loc = {filename: filename, line: uint, col: uint};
|
2011-07-05 04:48:19 -05:00
|
|
|
|
2011-08-19 17:16:48 -05:00
|
|
|
fn new_codemap() -> codemap { ret @{mutable files: []}; }
|
2011-07-16 01:01:10 -05:00
|
|
|
|
2012-01-25 16:53:45 -06:00
|
|
|
fn new_filemap(filename: filename, src: @str,
|
|
|
|
start_pos_ch: uint, start_pos_byte: uint)
|
2011-07-27 07:19:39 -05:00
|
|
|
-> filemap {
|
2012-01-25 16:53:45 -06:00
|
|
|
ret @{name: filename, src: src,
|
2011-07-27 07:19:39 -05:00
|
|
|
start_pos: {ch: start_pos_ch, byte: start_pos_byte},
|
2011-08-19 17:16:48 -05:00
|
|
|
mutable lines: [{ch: start_pos_ch, byte: start_pos_byte}]};
|
2011-07-05 04:48:19 -05:00
|
|
|
}
|
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
fn next_line(file: filemap, chpos: uint, byte_pos: uint) {
|
2011-08-19 17:16:48 -05:00
|
|
|
file.lines += [{ch: chpos, byte: byte_pos}];
|
2011-07-05 04:48:19 -05:00
|
|
|
}
|
|
|
|
|
2012-01-11 11:58:05 -06:00
|
|
|
type lookup_fn = fn@(file_pos) -> uint;
|
2011-07-05 04:48:19 -05:00
|
|
|
|
2012-01-25 15:22:10 -06:00
|
|
|
fn lookup_line(map: codemap, pos: uint, lookup: lookup_fn)
|
|
|
|
-> option::t<{fm: filemap, line: uint}>
|
|
|
|
{
|
2011-12-20 15:38:10 -06:00
|
|
|
let len = vec::len(map.files);
|
2011-07-27 07:19:39 -05:00
|
|
|
let a = 0u;
|
2011-12-20 15:38:10 -06:00
|
|
|
let b = len;
|
2011-07-27 07:19:39 -05:00
|
|
|
while b - a > 1u {
|
|
|
|
let m = (a + b) / 2u;
|
2011-08-19 17:16:48 -05:00
|
|
|
if lookup(map.files[m].start_pos) > pos { b = m; } else { a = m; }
|
2011-07-05 04:48:19 -05:00
|
|
|
}
|
2012-01-21 03:00:06 -06:00
|
|
|
if (a >= len) {
|
2012-01-25 15:22:10 -06:00
|
|
|
ret none;
|
2012-01-21 03:00:06 -06:00
|
|
|
}
|
2011-08-19 17:16:48 -05:00
|
|
|
let f = map.files[a];
|
2011-07-05 04:48:19 -05:00
|
|
|
a = 0u;
|
2011-08-15 18:38:23 -05:00
|
|
|
b = vec::len(f.lines);
|
2011-07-27 07:19:39 -05:00
|
|
|
while b - a > 1u {
|
|
|
|
let m = (a + b) / 2u;
|
2011-08-19 17:16:48 -05:00
|
|
|
if lookup(f.lines[m]) > pos { b = m; } else { a = m; }
|
2011-07-05 04:48:19 -05:00
|
|
|
}
|
2012-01-25 15:22:10 -06:00
|
|
|
ret some({fm: f, line: a});
|
|
|
|
}
|
|
|
|
|
|
|
|
fn lookup_pos(map: codemap, pos: uint, lookup: lookup_fn) -> loc {
|
|
|
|
alt lookup_line(map, pos, lookup) {
|
|
|
|
some({fm: f, line: a}) {
|
|
|
|
{filename: f.name, line: a + 1u, col: pos - lookup(f.lines[a])}
|
|
|
|
}
|
|
|
|
none {
|
|
|
|
{ filename: "-", line: 0u, col: 0u }
|
|
|
|
}
|
|
|
|
}
|
2011-07-16 01:01:10 -05:00
|
|
|
}
|
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
fn lookup_char_pos(map: codemap, pos: uint) -> loc {
|
|
|
|
fn lookup(pos: file_pos) -> uint { ret pos.ch; }
|
2011-07-16 01:01:10 -05:00
|
|
|
ret lookup_pos(map, pos, lookup);
|
|
|
|
}
|
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
fn lookup_byte_pos(map: codemap, pos: uint) -> loc {
|
|
|
|
fn lookup(pos: file_pos) -> uint { ret pos.byte; }
|
2011-07-16 01:01:10 -05:00
|
|
|
ret lookup_pos(map, pos, lookup);
|
2011-07-05 04:48:19 -05:00
|
|
|
}
|
|
|
|
|
2012-01-19 16:24:03 -06:00
|
|
|
enum opt_span {
|
2011-09-02 17:34:58 -05:00
|
|
|
|
2012-01-31 19:05:20 -06:00
|
|
|
//hack (as opposed to option), to make `span` compile
|
2012-01-19 19:56:05 -06:00
|
|
|
os_none,
|
|
|
|
os_some(@span),
|
2011-08-12 10:57:21 -05:00
|
|
|
}
|
|
|
|
type span = {lo: uint, hi: uint, expanded_from: opt_span};
|
2011-07-05 04:48:19 -05:00
|
|
|
|
2011-09-12 04:27:30 -05:00
|
|
|
fn span_to_str(sp: span, cm: codemap) -> str {
|
2011-08-12 10:57:21 -05:00
|
|
|
let cur = sp;
|
2011-09-02 17:34:58 -05:00
|
|
|
let res = "";
|
2011-08-12 10:57:21 -05:00
|
|
|
let prev_file = none;
|
2011-08-19 17:16:48 -05:00
|
|
|
while true {
|
2011-08-12 10:57:21 -05:00
|
|
|
let lo = lookup_char_pos(cm, cur.lo);
|
|
|
|
let hi = lookup_char_pos(cm, cur.hi);
|
2011-08-28 02:24:28 -05:00
|
|
|
res +=
|
2011-09-01 20:49:10 -05:00
|
|
|
#fmt["%s:%u:%u: %u:%u",
|
2011-08-19 17:16:48 -05:00
|
|
|
if some(lo.filename) == prev_file {
|
2011-09-02 17:34:58 -05:00
|
|
|
"-"
|
|
|
|
} else { lo.filename }, lo.line, lo.col, hi.line, hi.col];
|
2011-08-12 10:57:21 -05:00
|
|
|
alt cur.expanded_from {
|
2012-01-19 00:37:22 -06:00
|
|
|
os_none { break; }
|
2011-08-12 10:57:21 -05:00
|
|
|
os_some(new_sp) {
|
|
|
|
cur = *new_sp;
|
|
|
|
prev_file = some(lo.filename);
|
2011-09-02 17:34:58 -05:00
|
|
|
res += "<<";
|
2011-08-12 10:57:21 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret res;
|
2011-07-05 04:48:19 -05:00
|
|
|
}
|
|
|
|
|
2011-09-02 17:34:58 -05:00
|
|
|
type file_lines = {name: str, lines: [uint]};
|
2011-07-11 01:27:03 -05:00
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
fn span_to_lines(sp: span, cm: codemap::codemap) -> @file_lines {
|
|
|
|
let lo = lookup_char_pos(cm, sp.lo);
|
|
|
|
let hi = lookup_char_pos(cm, sp.hi);
|
2011-08-19 17:16:48 -05:00
|
|
|
let lines = [];
|
2011-10-21 05:31:48 -05:00
|
|
|
uint::range(lo.line - 1u, hi.line as uint) {|i| lines += [i]; };
|
2011-08-27 16:57:47 -05:00
|
|
|
ret @{name: lo.filename, lines: lines};
|
2011-07-11 01:27:03 -05:00
|
|
|
}
|
|
|
|
|
2012-02-01 05:45:44 -06:00
|
|
|
fn get_line(fm: filemap, line: int) -> str unsafe {
|
2011-08-19 17:16:48 -05:00
|
|
|
let begin: uint = fm.lines[line].byte - fm.start_pos.byte;
|
2011-07-27 07:19:39 -05:00
|
|
|
let end: uint;
|
2011-08-15 18:38:23 -05:00
|
|
|
if line as uint < vec::len(fm.lines) - 1u {
|
2011-08-19 17:16:48 -05:00
|
|
|
end = fm.lines[line + 1].byte - fm.start_pos.byte;
|
2011-07-13 14:19:59 -05:00
|
|
|
} else {
|
|
|
|
// If we're not done parsing the file, we're at the limit of what's
|
|
|
|
// parsed. If we just slice the rest of the string, we'll print out
|
|
|
|
// the remainder of the file, which is undesirable.
|
2012-01-25 16:53:45 -06:00
|
|
|
end = str::byte_len(*fm.src);
|
2012-02-01 06:20:21 -06:00
|
|
|
let rest = str::unsafe::slice_bytes(*fm.src, begin, end);
|
2011-09-01 19:27:58 -05:00
|
|
|
let newline = str::index(rest, '\n' as u8);
|
2011-07-27 07:19:39 -05:00
|
|
|
if newline != -1 { end = begin + (newline as uint); }
|
2011-07-11 01:27:03 -05:00
|
|
|
}
|
2012-02-01 06:20:21 -06:00
|
|
|
ret str::unsafe::slice_bytes(*fm.src, begin, end);
|
2011-07-11 01:27:03 -05:00
|
|
|
}
|
|
|
|
|
2012-01-25 15:22:10 -06:00
|
|
|
fn lookup_byte_offset(cm: codemap::codemap, chpos: uint)
|
|
|
|
-> {fm: filemap, pos: uint}
|
|
|
|
{
|
|
|
|
fn lookup(pos: file_pos) -> uint { ret pos.ch; }
|
|
|
|
let {fm,line} = option::get(lookup_line(cm,chpos,lookup));
|
|
|
|
let line_offset = fm.lines[line].byte;
|
|
|
|
let col = chpos - fm.lines[line].ch;
|
|
|
|
let col_offset = str::byte_len_range(*fm.src, line_offset, col);
|
|
|
|
ret {fm: fm, pos: line_offset + col_offset};
|
|
|
|
}
|
|
|
|
|
|
|
|
fn span_to_snippet(sp: span, cm: codemap::codemap) -> str {
|
|
|
|
let begin = lookup_byte_offset(cm,sp.lo);
|
|
|
|
let end = lookup_byte_offset(cm,sp.hi);
|
|
|
|
assert begin.fm == end.fm;
|
|
|
|
ret str::slice(*begin.fm.src, begin.pos, end.pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_snippet(cm: codemap::codemap, fidx: uint, lo: uint, hi: uint) -> str
|
|
|
|
{
|
|
|
|
let fm = cm.files[fidx];
|
|
|
|
ret str::slice(*fm.src, lo, hi)
|
|
|
|
}
|
|
|
|
|
2011-09-02 17:34:58 -05:00
|
|
|
fn get_filemap(cm: codemap, filename: str) -> filemap {
|
|
|
|
for fm: filemap in cm.files { if fm.name == filename { ret fm; } }
|
2011-07-11 01:27:03 -05:00
|
|
|
//XXjdm the following triggers a mismatched type bug
|
|
|
|
// (or expected function, found _|_)
|
2011-07-27 07:19:39 -05:00
|
|
|
fail; // ("asking for " + filename + " which we don't know about");
|
2011-07-11 01:27:03 -05:00
|
|
|
}
|
2012-01-26 03:52:08 -06:00
|
|
|
|
2011-07-05 04:48:19 -05:00
|
|
|
//
|
|
|
|
// Local Variables:
|
|
|
|
// mode: rust
|
|
|
|
// fill-column: 78;
|
|
|
|
// indent-tabs-mode: nil
|
|
|
|
// c-basic-offset: 4
|
|
|
|
// buffer-file-coding-system: utf-8-unix
|
|
|
|
// End:
|
|
|
|
//
|