Skip to main content

galvan_into_ast/
lib.rs

1use galvan_ast::{Ast, Point, RootItem, SegmentedAsts, Span, ToplevelItem};
2use galvan_files::Source;
3use galvan_parse::*;
4
5mod cursor_macro;
6mod items;
7mod modifiers;
8mod result;
9
10use result::CursorUtil;
11pub use result::{AstError, AstResult};
12
13pub trait IntoAst {
14    fn try_into_ast(self, source: Source) -> AstResult;
15}
16
17pub trait SourceIntoAst {
18    fn try_into_ast(self) -> AstResult;
19}
20
21pub trait ReadCursor: Sized {
22    fn read_cursor(cursor: &mut TreeCursor<'_>, source: &str) -> Result<Self, AstError>;
23}
24
25impl SourceIntoAst for Source {
26    fn try_into_ast(self) -> AstResult {
27        let parsed = parse_source(&self)?;
28        parsed.try_into_ast(self)
29    }
30}
31
32impl IntoAst for ParseTree {
33    fn try_into_ast(self, source: Source) -> AstResult {
34        let root = self.root_node();
35        let mut cursor = root.walk();
36
37        let mut ast = Ast {
38            toplevel: vec![],
39            source,
40        };
41
42        if cursor.child() {
43            let item = RootItem::read_cursor(&mut cursor, &ast.source)?;
44
45            ast.toplevel.push(item);
46
47            while cursor.next() {
48                let item = RootItem::read_cursor(&mut cursor, &ast.source)?;
49
50                ast.toplevel.push(item);
51            }
52        }
53
54        Ok(ast)
55    }
56}
57
58pub trait SegmentAst {
59    fn segmented(self) -> Result<SegmentedAsts, AstError>;
60}
61
62impl SegmentAst for Ast {
63    fn segmented(self) -> Result<SegmentedAsts, AstError> {
64        let mut types = Vec::new();
65        let mut functions = Vec::new();
66        let mut tests = Vec::new();
67        let mut main = None;
68
69        for item in self.toplevel {
70            match item {
71                RootItem::Type(item) => types.push(ToplevelItem {
72                    item,
73                    source: self.source.clone(),
74                }),
75                RootItem::Fn(item) => functions.push(ToplevelItem {
76                    item,
77                    source: self.source.clone(),
78                }),
79                RootItem::Test(item) => tests.push(ToplevelItem {
80                    item,
81                    source: self.source.clone(),
82                }),
83                RootItem::Main(item) => {
84                    if main.is_some() {
85                        return Err(AstError::DuplicateMain);
86                    }
87
88                    main = Some(ToplevelItem {
89                        item,
90                        source: self.source.clone(),
91                    })
92                }
93            }
94        }
95
96        Ok(SegmentedAsts {
97            types,
98            functions,
99            tests,
100            main,
101        })
102    }
103}
104
105impl SegmentAst for Vec<Ast> {
106    fn segmented(self) -> Result<SegmentedAsts, AstError> {
107        let mut types = Vec::new();
108        let mut functions = Vec::new();
109        let mut tests = Vec::new();
110        let mut main = None;
111        let segmented = self.into_iter().map(SegmentAst::segmented);
112
113        for ast in segmented {
114            let ast = ast?;
115            types.extend(ast.types);
116            functions.extend(ast.functions);
117            tests.extend(ast.tests);
118            if let Some(main_decl) = ast.main {
119                if main.is_some() {
120                    return Err(AstError::DuplicateMain);
121                }
122
123                main = Some(main_decl);
124            }
125        }
126
127        Ok(SegmentedAsts {
128            types,
129            functions,
130            tests,
131            main,
132        })
133    }
134}
135
136pub trait SpanExt {
137    fn from_node(node: Node<'_>) -> Span;
138}
139
140impl SpanExt for Span {
141    fn from_node(node: Node<'_>) -> Span {
142        let start_byte = node.start_byte();
143        let end_byte = node.end_byte();
144        let start_point = node.start_position();
145        let end_point = node.end_position();
146
147        let start = Point {
148            row: start_point.row,
149            col: start_point.column,
150        };
151        let end = Point {
152            row: end_point.row,
153            col: end_point.column,
154        };
155
156        Span {
157            range: (start_byte, end_byte),
158            start,
159            end,
160        }
161    }
162}