1use koto_lexer::Span;
2use std::{fmt, num::TryFromIntError};
3
4use crate::{ConstantPool, Node, error::*};
5
6#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
8pub struct AstIndex(u32);
9
10impl From<AstIndex> for u32 {
11 fn from(value: AstIndex) -> Self {
12 value.0
13 }
14}
15
16impl From<AstIndex> for usize {
17 fn from(value: AstIndex) -> Self {
18 value.0 as usize
19 }
20}
21
22impl From<u32> for AstIndex {
23 fn from(value: u32) -> Self {
24 Self(value)
25 }
26}
27
28impl From<&u32> for AstIndex {
29 fn from(value: &u32) -> Self {
30 Self(*value)
31 }
32}
33
34impl TryFrom<usize> for AstIndex {
35 type Error = TryFromIntError;
36
37 fn try_from(value: usize) -> std::result::Result<Self, Self::Error> {
38 Ok(Self(u32::try_from(value)?))
39 }
40}
41
42impl fmt::Display for AstIndex {
43 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44 write!(f, "{}", self.0)
45 }
46}
47
48#[derive(Clone, Debug, Default)]
50pub struct AstNode {
51 pub node: Node,
53 pub span: AstIndex,
57}
58
59#[derive(Debug, Default, Clone)]
63pub struct Ast {
64 nodes: Vec<AstNode>,
65 spans: Vec<Span>,
66 constants: ConstantPool,
67}
68
69impl Ast {
70 pub fn with_capacity(capacity: usize) -> Self {
72 Self {
73 nodes: Vec::with_capacity(capacity),
74 spans: Vec::with_capacity(capacity),
75 constants: ConstantPool::default(),
76 }
77 }
78
79 pub fn push(&mut self, node: Node, span: Span) -> Result<AstIndex> {
81 self.spans.push(span);
84 let span_index = AstIndex::try_from(self.spans.len() - 1)
85 .map_err(|_| Error::new(InternalError::AstCapacityOverflow.into(), span))?;
86
87 self.nodes.push(AstNode {
88 node,
89 span: span_index,
90 });
91 AstIndex::try_from(self.nodes.len() - 1)
92 .map_err(|_| Error::new(InternalError::AstCapacityOverflow.into(), span))
93 }
94
95 pub fn node(&self, index: AstIndex) -> &AstNode {
97 &self.nodes[usize::from(index)]
98 }
99
100 pub fn span(&self, index: AstIndex) -> &Span {
102 &self.spans[usize::from(index)]
103 }
104
105 pub fn constants(&self) -> &ConstantPool {
107 &self.constants
108 }
109
110 pub fn consume_constants(self) -> ConstantPool {
115 self.constants
116 }
117
118 pub(crate) fn set_constants(&mut self, constants: ConstantPool) {
119 self.constants = constants
120 }
121
122 pub fn entry_point(&self) -> Option<AstIndex> {
124 if self.nodes.is_empty() {
125 None
126 } else {
127 AstIndex::try_from(self.nodes.len() - 1).ok()
128 }
129 }
130
131 pub fn nodes(&self) -> &[AstNode] {
133 &self.nodes
134 }
135}