neyuki 0.6.0

A small Lua-like scripting language implemented in Rust
//! Source positions of syntax tree nodes.

#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub struct SourceLocation {
    pub line: u32,
    pub column: u32,
}

impl SourceLocation {
    pub fn new(line: u32, column: u32) -> Self {
        Self { line, column }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub struct Span {
    pub start: SourceLocation,
    pub end: SourceLocation,
}

impl Span {
    pub fn new(start: SourceLocation, end: SourceLocation) -> Self {
        Self { start, end }
    }

    pub fn point(line: u32, column: u32) -> Self {
        let loc = SourceLocation::new(line, column);
        Self {
            start: loc,
            end: loc,
        }
    }

    pub fn dummy() -> Self {
        Self::default()
    }

    pub fn combine(self, other: Self) -> Self {
        if self == Self::default() {
            return other;
        }
        if other == Self::default() {
            return self;
        }
        let start = if self.start.line < other.start.line
            || (self.start.line == other.start.line && self.start.column <= other.start.column)
        {
            self.start
        } else {
            other.start
        };
        let end = if self.end.line > other.end.line
            || (self.end.line == other.end.line && self.end.column >= other.end.column)
        {
            self.end
        } else {
            other.end
        };
        Self { start, end }
    }
}

impl std::fmt::Display for SourceLocation {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}:{}", self.line, self.column)
    }
}

impl std::fmt::Display for Span {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}-{}", self.start, self.end)
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SpannedNode<T> {
    pub node: T,
    pub span: Span,
    pub id: crate::ast::node_id::NodeId,
}

impl<T> SpannedNode<T> {
    pub fn new(node: T, span: Span) -> Self {
        Self {
            node,
            span,
            id: crate::ast::node_id::NodeId::next(),
        }
    }

    pub fn with_id(node: T, span: Span, id: crate::ast::node_id::NodeId) -> Self {
        Self { node, span, id }
    }
}

use crate::ast::node_id::NodeId;
use std::collections::HashMap;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SpanPool {
    map: HashMap<NodeId, Span>,
}

impl SpanPool {
    pub fn new() -> Self {
        Self {
            map: HashMap::new(),
        }
    }

    pub fn insert(&mut self, id: NodeId, span: Span) {
        self.map.insert(id, span);
    }

    pub fn get(&self, id: NodeId) -> Option<Span> {
        self.map.get(&id).copied()
    }

    pub fn get_or_dummy(&self, id: NodeId) -> Span {
        self.map.get(&id).copied().unwrap_or_default()
    }

    /// The line each node starts on.
    pub fn start_lines(&self) -> HashMap<NodeId, u32> {
        self.map
            .iter()
            .map(|(id, span)| (*id, span.start.line))
            .collect()
    }
}

impl Default for SpanPool {
    fn default() -> Self {
        Self::new()
    }
}