syntax v2
introduce a new, more ergonomic syntax for haku not all features are implemented just yet. still missing: - custom tags (non-True/False) - color literals - lists
This commit is contained in:
parent
a3e5e8bd10
commit
2595bf0d82
21 changed files with 2844 additions and 1062 deletions
125
crates/haku/src/ast.rs
Normal file
125
crates/haku/src/ast.rs
Normal file
|
@ -0,0 +1,125 @@
|
|||
use core::{error::Error, fmt::Display};
|
||||
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use crate::source::Span;
|
||||
|
||||
pub mod dump;
|
||||
pub mod walk;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct NodeId(u32);
|
||||
|
||||
impl NodeId {
|
||||
pub const NIL: NodeId = NodeId(0);
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum NodeKind {
|
||||
Nil,
|
||||
|
||||
Token,
|
||||
|
||||
Ident,
|
||||
Tag,
|
||||
Number,
|
||||
Color,
|
||||
List,
|
||||
|
||||
Op,
|
||||
Unary,
|
||||
Binary,
|
||||
Call,
|
||||
ParenEmpty,
|
||||
Paren,
|
||||
Lambda,
|
||||
Params,
|
||||
Param,
|
||||
If,
|
||||
Let,
|
||||
|
||||
Toplevel,
|
||||
|
||||
Error,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Node {
|
||||
pub span: Span,
|
||||
pub kind: NodeKind,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Ast {
|
||||
kinds: Vec<NodeKind>,
|
||||
spans: Vec<Span>,
|
||||
children_spans: Vec<(u32, u32)>,
|
||||
children: Vec<NodeId>,
|
||||
}
|
||||
|
||||
impl Ast {
|
||||
pub fn new(capacity: usize) -> Self {
|
||||
assert!(capacity >= 1, "there must be space for at least a nil node");
|
||||
assert!(capacity <= u32::MAX as usize);
|
||||
|
||||
let mut ast = Self {
|
||||
kinds: Vec::with_capacity(capacity),
|
||||
spans: Vec::with_capacity(capacity),
|
||||
children_spans: Vec::with_capacity(capacity),
|
||||
children: Vec::new(),
|
||||
};
|
||||
|
||||
ast.alloc(NodeKind::Nil, Span::new(0, 0)).unwrap();
|
||||
|
||||
ast
|
||||
}
|
||||
|
||||
pub fn alloc(&mut self, kind: NodeKind, span: Span) -> Result<NodeId, NodeAllocError> {
|
||||
if self.kinds.len() >= self.kinds.capacity() {
|
||||
return Err(NodeAllocError);
|
||||
}
|
||||
|
||||
let index = self.kinds.len() as u32;
|
||||
self.kinds.push(kind);
|
||||
self.spans.push(span);
|
||||
self.children_spans.push((0, 0));
|
||||
Ok(NodeId(index))
|
||||
}
|
||||
|
||||
// NOTE: This never produces a NodeAllocError, because there can more or less only ever be as many children for
|
||||
// nodes as there are nodes.
|
||||
pub fn alloc_children(&mut self, for_node: NodeId, children: &[NodeId]) {
|
||||
let start = self.children.len();
|
||||
self.children.extend_from_slice(children);
|
||||
let end = self.children.len();
|
||||
self.children_spans[for_node.0 as usize] = (start as u32, end as u32);
|
||||
}
|
||||
|
||||
pub fn extend_span(&mut self, in_node: NodeId, end: u32) {
|
||||
self.spans[in_node.0 as usize].end = end;
|
||||
}
|
||||
|
||||
pub fn kind(&self, id: NodeId) -> NodeKind {
|
||||
self.kinds[id.0 as usize]
|
||||
}
|
||||
|
||||
pub fn span(&self, id: NodeId) -> Span {
|
||||
self.spans[id.0 as usize]
|
||||
}
|
||||
|
||||
pub fn children(&self, id: NodeId) -> &[NodeId] {
|
||||
let (start, end) = self.children_spans[id.0 as usize];
|
||||
&self.children[start as usize..end as usize]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct NodeAllocError;
|
||||
|
||||
impl Display for NodeAllocError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.write_str("too many nodes")
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for NodeAllocError {}
|
Loading…
Add table
Add a link
Reference in a new issue