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