use crate::parser::{ast::NodeDecl, diagnostic::Diagnostics};
pub mod ast;
pub mod diagnostic;
pub(crate) mod expr;
mod lines;
pub use ast::parse;
pub const END_NODE_NAME: &str = "END";
pub const RESERVED_NODE_NAMES: &[&str] = &[END_NODE_NAME];
pub const AWAIT_KEYWORD: &str = "await";
pub const RESERVED_COMMAND_NAMES: &[&str] = &[AWAIT_KEYWORD];
#[derive(Debug)]
pub struct Parsed {
pub nodes: Vec<NodeDecl>,
pub diagnostics: Diagnostics,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Span {
pub start: usize,
pub end: usize,
}
impl Span {
pub fn new(start: usize, end: usize) -> Self {
Self { start, end }
}
pub fn from_length(start: usize, length: usize) -> Self {
Self {
start,
end: start + length,
}
}
pub fn length(&self) -> usize {
self.end - self.start
}
pub fn join(self, other: Span) -> Self {
Self {
start: self.start.min(other.start),
end: self.end.max(other.end),
}
}
}
#[derive(Debug, Clone)]
pub struct LineIndex {
line_starts: Vec<usize>,
}
impl LineIndex {
pub fn new(src: &str) -> Self {
let mut line_starts = vec![0];
line_starts.extend(src.match_indices('\n').map(|(i, _)| i + 1));
Self { line_starts }
}
pub fn line_count(&self) -> usize {
self.line_starts.len()
}
pub fn line_text<'a>(&self, src: &'a str, line: usize) -> &'a str {
let start = self.line_starts[line];
if let Some(&end) = self.line_starts.get(line + 1) {
&src[start..end]
} else {
&src[start..]
}
}
pub fn line_of(&self, offset: usize) -> usize {
match self.line_starts.binary_search(&offset) {
Ok(line) => line,
Err(next) => next - 1,
}
}
fn line_start(&self, line: usize) -> usize {
self.line_starts[line.min(self.line_starts.len() - 1)]
}
pub fn line_col(&self, offset: usize) -> (usize, usize) {
let line = self.line_of(offset);
(line, offset - self.line_start(line))
}
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Spanned<T> {
pub value: T,
pub span: Span,
}
impl<'a> Spanned<&'a str> {
fn from_text(text: &'a str, offset: usize) -> Self {
let rest = text.trim_start();
let start = offset + text.len() - rest.len();
let rest = rest.trim();
Self {
value: rest,
span: Span::from_length(start, rest.len()),
}
}
}
impl From<Spanned<&str>> for Spanned<String> {
fn from(value: Spanned<&str>) -> Self {
Self {
value: value.value.into(),
span: value.span,
}
}
}
impl<T> Spanned<T> {
pub fn new(value: T, span: Span) -> Self {
Self { value, span }
}
pub fn into_inner(self) -> T {
self.value
}
}