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:
りき萌 2024-08-27 20:43:14 +02:00
parent a3e5e8bd10
commit 2595bf0d82
21 changed files with 2844 additions and 1062 deletions

View 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
}

View 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
}
}
}