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
34
crates/haku/src/ast/dump.rs
Normal file
34
crates/haku/src/ast/dump.rs
Normal file
|
@ -0,0 +1,34 @@
|
|||
use alloc::string::String;
|
||||
use core::fmt::Write;
|
||||
|
||||
use crate::{ast::NodeKind, source::SourceCode};
|
||||
|
||||
use super::{Ast, NodeId};
|
||||
|
||||
pub fn dump(ast: &Ast, node: NodeId, code: Option<&SourceCode>) -> String {
|
||||
let mut result = String::new();
|
||||
|
||||
fn rec(ast: &Ast, node: NodeId, code: Option<&SourceCode>, result: &mut String, depth: usize) {
|
||||
for _ in 0..depth {
|
||||
result.push_str(" ");
|
||||
}
|
||||
|
||||
write!(result, "{:?} @ {:?}", ast.kind(node), ast.span(node)).unwrap();
|
||||
if let Some(code) = code {
|
||||
if ast.kind(node) == NodeKind::Token {
|
||||
write!(result, " {:?}", ast.span(node).slice(code)).unwrap();
|
||||
}
|
||||
}
|
||||
writeln!(result).unwrap();
|
||||
for &child in ast.children(node) {
|
||||
rec(ast, child, code, result, depth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
rec(ast, node, code, &mut result, 0);
|
||||
|
||||
// Remove the trailing newline.
|
||||
result.pop();
|
||||
|
||||
result
|
||||
}
|
73
crates/haku/src/ast/walk.rs
Normal file
73
crates/haku/src/ast/walk.rs
Normal file
|
@ -0,0 +1,73 @@
|
|||
use super::{Ast, NodeId, NodeKind};
|
||||
|
||||
impl Ast {
|
||||
pub fn child(&self, parent: NodeId, kind: NodeKind) -> Option<NodeId> {
|
||||
self.children(parent)
|
||||
.iter()
|
||||
.find(|&&child| self.kind(child) == kind)
|
||||
.copied()
|
||||
}
|
||||
|
||||
pub fn walk(&self, parent: NodeId) -> Walk<'_> {
|
||||
Walk {
|
||||
ast: self,
|
||||
parent,
|
||||
index: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over a node's children, with convenience methods for accessing those children.
|
||||
#[derive(Clone)]
|
||||
pub struct Walk<'a> {
|
||||
ast: &'a Ast,
|
||||
parent: NodeId,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl<'a> Walk<'a> {
|
||||
/// Walk to the first non-Nil, non-Error, non-Token node.
|
||||
pub fn node(&mut self) -> Option<NodeId> {
|
||||
while let Some(id) = self.next() {
|
||||
if !matches!(
|
||||
self.ast.kind(id),
|
||||
NodeKind::Nil | NodeKind::Token | NodeKind::Error
|
||||
) {
|
||||
return Some(id);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Walk to the next [`node`][`Self::node`] of the given kind.
|
||||
pub fn node_of(&mut self, kind: NodeKind) -> Option<NodeId> {
|
||||
while let Some(id) = self.node() {
|
||||
if self.ast.kind(id) == kind {
|
||||
return Some(id);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Find the first node of the given kind. This does not advance the iterator.
|
||||
pub fn get(&self, kind: NodeKind) -> Option<NodeId> {
|
||||
self.clone().find(|&id| self.ast.kind(id) == kind)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Walk<'a> {
|
||||
type Item = NodeId;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let children = self.ast.children(self.parent);
|
||||
if self.index < children.len() {
|
||||
let index = self.index;
|
||||
self.index += 1;
|
||||
Some(children[index])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue