tree lexer
This commit is contained in:
parent
bc0acf7e19
commit
3bbf9d67ec
|
@ -89,7 +89,7 @@ macro_rules! tokens {
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
$vis enum $ty_name {
|
$vis enum $ty_name {
|
||||||
$($name,
|
$($name,
|
||||||
)*
|
)*
|
||||||
|
@ -442,3 +442,99 @@ impl LexemeParser {
|
||||||
self.lexemes.candidates().last().copied()
|
self.lexemes.candidates().last().copied()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// but what if...? tree!
|
||||||
|
mod tree {
|
||||||
|
use super::Token;
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
struct Node {
|
||||||
|
keys: Vec<char>,
|
||||||
|
values: Vec<Option<Token>>,
|
||||||
|
edges: Vec<Option<Box<Node>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Tree {
|
||||||
|
root: Option<Box<Node>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_tree() -> Tree {
|
||||||
|
let lexemes = Token::lexemes()
|
||||||
|
.iter()
|
||||||
|
.map(|(tok, _)| tok.clone())
|
||||||
|
.collect::<Box<_>>();
|
||||||
|
|
||||||
|
let mut tree = Tree {
|
||||||
|
root: Some(Box::new(Node::default())),
|
||||||
|
};
|
||||||
|
|
||||||
|
for tok in lexemes {
|
||||||
|
let lexeme = tok.lexeme().unwrap();
|
||||||
|
let mut current = &mut Box::new(Node::default());
|
||||||
|
let mut next = &mut tree.root;
|
||||||
|
let mut p = 0;
|
||||||
|
for c in lexeme.chars() {
|
||||||
|
current = next.get_or_insert(Box::new(Node::default()));
|
||||||
|
p = match current.keys.binary_search(&c) {
|
||||||
|
Ok(p) => p,
|
||||||
|
Err(p) => {
|
||||||
|
current.keys.insert(p, c);
|
||||||
|
current.values.insert(p, None);
|
||||||
|
current.edges.insert(p, None);
|
||||||
|
p
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
next = current.edges.get_mut(p).unwrap();
|
||||||
|
}
|
||||||
|
current.values[p] = Some(tok);
|
||||||
|
}
|
||||||
|
|
||||||
|
tree
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_tree(tree: &Tree, mut tokens: impl Iterator<Item = char>) -> Option<Token> {
|
||||||
|
let mut current = tree.root.as_ref().unwrap();
|
||||||
|
let mut p = 0;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let Some(ch) = tokens.next() else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
if crate::is_things::is_whitespace(ch) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = match current.keys.binary_search(&ch) {
|
||||||
|
Ok(p) => p,
|
||||||
|
Err(p) => {
|
||||||
|
eprintln!("No match for {ch} in {:?} (p={p})", current.keys);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
current = match current.edges.get(p) {
|
||||||
|
Some(Some(node)) => node,
|
||||||
|
_ => break,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
eprintln!("current: {:?}", current);
|
||||||
|
current.values.get(p).copied().flatten()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tree_tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tree() {
|
||||||
|
let tree = build_tree();
|
||||||
|
eprintln!("Tree: {tree:?}");
|
||||||
|
let tokens = "fn let void";
|
||||||
|
assert_eq!(search_tree(&tree, tokens.chars()), Some(Token::Fn));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue