1#![allow(missing_docs)]
7
8use microcad_syntax::Span;
9use crate::{parse::*, src_ref::*};
10
11#[derive(Clone)]
12pub struct LineIndex {
13 line_offsets: Vec<usize>,
15}
16
17impl LineIndex {
18 pub fn new(text: &str) -> LineIndex {
19 let mut line_offsets: Vec<usize> = vec![0];
20
21 let mut offset = 0;
22
23 for c in text.chars() {
24 offset += c.len_utf8();
25 if c == '\n' {
26 line_offsets.push(offset);
27 }
28 }
29
30 LineIndex { line_offsets }
31 }
32
33 pub fn line_col(&self, input: &str, pos: usize) -> (usize, usize) {
37 let line = self.line_offsets.partition_point(|&it| it <= pos) - 1;
38 let first_offset = self.line_offsets[line];
39
40 let line_str = &input[first_offset..pos];
42 let col = line_str.chars().count();
43
44 (line + 1, col + 1)
45 }
46}
47
48pub struct ParseContext<'source> {
49 pub source: &'source str,
50 pub source_file_hash: u64,
51 line_index: LineIndex,
52}
53
54impl<'source> ParseContext<'source> {
55 pub fn new(source: &'source str) -> Self {
56 let source_file_hash = {
57 use std::hash::{Hash, Hasher};
58 let mut hasher = rustc_hash::FxHasher::default();
59 source.hash(&mut hasher);
60 hasher.finish()
61 };
62 ParseContext {
63 source,
64 source_file_hash,
65 line_index: LineIndex::new(source),
66 }
67 }
68
69 pub fn src_ref(&self, span: &Span) -> SrcRef {
70 let (line, col) = self.line_index.line_col(self.source, span.start);
71 SrcRef::new(span.clone(), line, col, self.source_file_hash)
72 }
73}
74
75pub trait FromAst: Sized {
76 type AstNode;
77
78 fn from_ast(node: &Self::AstNode, context: &ParseContext) -> Result<Self, ParseError>;
79}