1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/// Position in a syntax context.
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub struct Pos {
    pub index: u32,
}

/// A syntax context index.
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub struct SyntaxCtxIndex(pub usize);

impl SyntaxCtxIndex {
    pub fn new(size: usize) -> SyntaxCtxIndex {
        SyntaxCtxIndex(size)
    }
}

/// A span in the encoded format that is required by
/// kind2.
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub struct EncodedRange(pub u64);

/// Describes a position in a source code (syntax context). It's useful
/// to generate error messages.
#[derive(Clone, Debug, Copy, Hash, PartialEq, Eq)]
pub struct Range {
    pub start: Pos,
    pub end: Pos,
    pub ctx: SyntaxCtxIndex,
}

pub trait Locatable {
    fn locate(&self) -> Range;
}

impl Range {
    #[inline]
    pub fn new(start: Pos, end: Pos, ctx: SyntaxCtxIndex) -> Range {
        Range { start, end, ctx }
    }

    pub fn ghost_range() -> Range {
        Range::new(Pos { index: 0 }, Pos { index: 0 }, SyntaxCtxIndex(0))
    }

    /// Joins two ranges. It keeps the syntax context
    /// of the first one.
    #[inline]
    pub fn mix(&self, next: Range) -> Range {
        Range {
            start: self.start,
            end: next.end,
            ctx: self.ctx,
        }
    }

    /// Sets the context of the range,
    #[inline]
    pub fn set_ctx(&self, ctx: SyntaxCtxIndex) -> Range {
        Range {
            start: self.start,
            end: self.end,
            ctx,
        }
    }

    #[inline]
    pub fn encode(&self) -> EncodedRange {
        EncodedRange(
            ((self.ctx.0 as u64) << 48)
                | ((self.start.index as u64) & 0xFFFFFF)
                | (((self.end.index as u64) & 0xFFFFFF) << 24),
        )
    }
}

impl EncodedRange {
    /// Transforms a encoded span back into a range.
    pub fn to_range(&self) -> Range {
        Range {
            ctx: SyntaxCtxIndex((self.0 >> 48) as usize),
            start: Pos {
                index: (self.0 & 0xFFFFFF) as u32,
            },
            end: Pos {
                index: ((self.0 >> 24) & 0xFFFFFF) as u32,
            },
        }
    }
}