1
Fork 0
mirror of https://github.com/RGBCube/cstree synced 2025-07-27 09:07:44 +00:00

rename SyntaxKind variants in examples

(fixes new clippy lint going off)
This commit is contained in:
Domenic Quirl 2021-03-31 10:19:57 +02:00
parent 159eec3f6e
commit 76614f3e82
2 changed files with 99 additions and 96 deletions

View file

@ -20,20 +20,19 @@ use cstree::{
use std::iter::Peekable; use std::iter::Peekable;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[allow(non_camel_case_types)]
#[repr(u16)] #[repr(u16)]
enum SyntaxKind { enum SyntaxKind {
WHITESPACE = 0, Whitespace = 0,
ADD, Add,
SUB, Sub,
MUL, Mul,
DIV, Div,
NUMBER, Number,
ERROR, Error,
OPERATION, Operation,
ROOT, Root,
} }
use SyntaxKind::*; use SyntaxKind::*;
@ -49,7 +48,7 @@ impl cstree::Language for Lang {
type Kind = SyntaxKind; type Kind = SyntaxKind;
fn kind_from_raw(raw: cstree::SyntaxKind) -> Self::Kind { fn kind_from_raw(raw: cstree::SyntaxKind) -> Self::Kind {
assert!(raw.0 <= ROOT as u16); assert!(raw.0 <= Root as u16);
unsafe { std::mem::transmute::<u16, SyntaxKind>(raw.0) } unsafe { std::mem::transmute::<u16, SyntaxKind>(raw.0) }
} }
@ -71,7 +70,7 @@ struct Parser<'input, I: Iterator<Item = (SyntaxKind, &'input str)>> {
} }
impl<'input, I: Iterator<Item = (SyntaxKind, &'input str)>> Parser<'input, I> { impl<'input, I: Iterator<Item = (SyntaxKind, &'input str)>> Parser<'input, I> {
fn peek(&mut self) -> Option<SyntaxKind> { fn peek(&mut self) -> Option<SyntaxKind> {
while self.iter.peek().map(|&(t, _)| t == WHITESPACE).unwrap_or(false) { while self.iter.peek().map(|&(t, _)| t == Whitespace).unwrap_or(false) {
self.bump(); self.bump();
} }
self.iter.peek().map(|&(t, _)| t) self.iter.peek().map(|&(t, _)| t)
@ -85,9 +84,9 @@ impl<'input, I: Iterator<Item = (SyntaxKind, &'input str)>> Parser<'input, I> {
fn parse_val(&mut self) { fn parse_val(&mut self) {
match self.peek() { match self.peek() {
Some(NUMBER) => self.bump(), Some(Number) => self.bump(),
_ => { _ => {
self.builder.start_node(ERROR.into()); self.builder.start_node(Error.into());
self.bump(); self.bump();
self.builder.finish_node(); self.builder.finish_node();
} }
@ -98,7 +97,7 @@ impl<'input, I: Iterator<Item = (SyntaxKind, &'input str)>> Parser<'input, I> {
let checkpoint = self.builder.checkpoint(); let checkpoint = self.builder.checkpoint();
next(self); next(self);
while self.peek().map(|t| tokens.contains(&t)).unwrap_or(false) { while self.peek().map(|t| tokens.contains(&t)).unwrap_or(false) {
self.builder.start_node_at(checkpoint, OPERATION.into()); self.builder.start_node_at(checkpoint, Operation.into());
self.bump(); self.bump();
next(self); next(self);
self.builder.finish_node(); self.builder.finish_node();
@ -106,15 +105,15 @@ impl<'input, I: Iterator<Item = (SyntaxKind, &'input str)>> Parser<'input, I> {
} }
fn parse_mul(&mut self) { fn parse_mul(&mut self) {
self.handle_operation(&[MUL, DIV], Self::parse_val) self.handle_operation(&[Mul, Div], Self::parse_val)
} }
fn parse_add(&mut self) { fn parse_add(&mut self) {
self.handle_operation(&[ADD, SUB], Self::parse_mul) self.handle_operation(&[Add, Sub], Self::parse_mul)
} }
fn parse(mut self) -> (SyntaxNode, impl Resolver) { fn parse(mut self) -> (SyntaxNode, impl Resolver) {
self.builder.start_node(ROOT.into()); self.builder.start_node(Root.into());
self.parse_add(); self.parse_add();
self.builder.finish_node(); self.builder.finish_node();
@ -143,19 +142,19 @@ fn main() {
builder: GreenNodeBuilder::new(), builder: GreenNodeBuilder::new(),
iter: vec![ iter: vec![
// 1 + 2 * 3 + 4 // 1 + 2 * 3 + 4
(NUMBER, "1"), (Number, "1"),
(WHITESPACE, " "), (Whitespace, " "),
(ADD, "+"), (Add, "+"),
(WHITESPACE, " "), (Whitespace, " "),
(NUMBER, "2"), (Number, "2"),
(WHITESPACE, " "), (Whitespace, " "),
(MUL, "*"), (Mul, "*"),
(WHITESPACE, " "), (Whitespace, " "),
(NUMBER, "3"), (Number, "3"),
(WHITESPACE, " "), (Whitespace, " "),
(ADD, "+"), (Add, "+"),
(WHITESPACE, " "), (Whitespace, " "),
(NUMBER, "4"), (Number, "4"),
] ]
.into_iter() .into_iter()
.peekable(), .peekable(),

View file

@ -9,19 +9,18 @@
/// Let's start with defining all kinds of tokens and composite nodes. /// Let's start with defining all kinds of tokens and composite nodes.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[allow(non_camel_case_types)]
#[repr(u16)] #[repr(u16)]
enum SyntaxKind { pub enum SyntaxKind {
L_PAREN = 0, // '(' LParen = 0, // '('
R_PAREN, // ')' RParen, // ')'
WORD, // '+', '15' Word, // '+', '15'
WHITESPACE, // whitespaces is explicit Whitespace, // whitespaces is explicit
ERROR, // as well as errors Error, // as well as errors
// composite nodes // composite nodes
LIST, // `(+ 2 3)` List, // `(+ 2 3)`
ATOM, // `+`, `15`, wraps a WORD token Atom, // `+`, `15`, wraps a WORD token
ROOT, // top-level node: a list of s-expressions Root, // top-level node: a list of s-expressions
} }
use std::collections::VecDeque; use std::collections::VecDeque;
@ -41,12 +40,12 @@ impl From<SyntaxKind> for cstree::SyntaxKind {
/// types, allowing for a nicer SyntaxNode API where "kinds" are values from our `enum SyntaxKind`, /// types, allowing for a nicer SyntaxNode API where "kinds" are values from our `enum SyntaxKind`,
/// instead of plain u16 values. /// instead of plain u16 values.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
enum Lang {} pub enum Lang {}
impl cstree::Language for Lang { impl cstree::Language for Lang {
type Kind = SyntaxKind; type Kind = SyntaxKind;
fn kind_from_raw(raw: cstree::SyntaxKind) -> Self::Kind { fn kind_from_raw(raw: cstree::SyntaxKind) -> Self::Kind {
assert!(raw.0 <= ROOT as u16); assert!(raw.0 <= Root as u16);
unsafe { std::mem::transmute::<u16, SyntaxKind>(raw.0) } unsafe { std::mem::transmute::<u16, SyntaxKind>(raw.0) }
} }
@ -103,13 +102,13 @@ fn parse(text: &str) -> Parse<impl Resolver> {
impl Parser<'_> { impl Parser<'_> {
fn parse(mut self) -> Parse<impl Resolver> { fn parse(mut self) -> Parse<impl Resolver> {
// Make sure that the root node covers all source // Make sure that the root node covers all source
self.builder.start_node(ROOT.into()); self.builder.start_node(Root.into());
// Parse zero or more S-expressions // Parse zero or more S-expressions
loop { loop {
match self.sexp() { match self.sexp() {
SexpRes::Eof => break, SexpRes::Eof => break,
SexpRes::RParen => { SexpRes::RParen => {
self.builder.start_node(ERROR.into()); self.builder.start_node(Error.into());
self.errors.push("unmatched `)`".to_string()); self.errors.push("unmatched `)`".to_string());
self.bump(); // be sure to advance even in case of an error, so as to not get stuck self.bump(); // be sure to advance even in case of an error, so as to not get stuck
self.builder.finish_node(); self.builder.finish_node();
@ -134,9 +133,9 @@ fn parse(text: &str) -> Parse<impl Resolver> {
} }
fn list(&mut self) { fn list(&mut self) {
assert_eq!(self.current(), Some(L_PAREN)); assert_eq!(self.current(), Some(LParen));
// Start the list node // Start the list node
self.builder.start_node(LIST.into()); self.builder.start_node(List.into());
self.bump(); // '(' self.bump(); // '('
loop { loop {
match self.sexp() { match self.sexp() {
@ -161,17 +160,17 @@ fn parse(text: &str) -> Parse<impl Resolver> {
// Either a list, an atom, a closing paren, or an eof. // Either a list, an atom, a closing paren, or an eof.
let t = match self.current() { let t = match self.current() {
None => return SexpRes::Eof, None => return SexpRes::Eof,
Some(R_PAREN) => return SexpRes::RParen, Some(RParen) => return SexpRes::RParen,
Some(t) => t, Some(t) => t,
}; };
match t { match t {
L_PAREN => self.list(), LParen => self.list(),
WORD => { Word => {
self.builder.start_node(ATOM.into()); self.builder.start_node(Atom.into());
self.bump(); self.bump();
self.builder.finish_node(); self.builder.finish_node();
} }
ERROR => self.bump(), Error => self.bump(),
_ => unreachable!(), _ => unreachable!(),
} }
SexpRes::Ok SexpRes::Ok
@ -189,7 +188,7 @@ fn parse(text: &str) -> Parse<impl Resolver> {
} }
fn skip_ws(&mut self) { fn skip_ws(&mut self) {
while self.current() == Some(WHITESPACE) { while self.current() == Some(Whitespace) {
self.bump() self.bump()
} }
} }
@ -232,7 +231,7 @@ fn test_parser() {
assert_eq!( assert_eq!(
// note how, since we didn't attach the resolver in `syntax`, we now need to provide it // note how, since we didn't attach the resolver in `syntax`, we now need to provide it
node.debug(resolver, false), node.debug(resolver, false),
"ROOT@0..15", // root node, spanning 15 bytes "Root@0..15", // root node, spanning 15 bytes
); );
assert_eq!(node.children().count(), 1); assert_eq!(node.children().count(), 1);
let list = node.children().next().unwrap(); let list = node.children().next().unwrap();
@ -244,13 +243,13 @@ fn test_parser() {
assert_eq!( assert_eq!(
children, children,
vec![ vec![
"L_PAREN@0..1".to_string(), "LParen@0..1".to_string(),
"ATOM@1..2".to_string(), "Atom@1..2".to_string(),
"WHITESPACE@2..3".to_string(), // note, explicit whitespace! "Whitespace@2..3".to_string(), // note, explicit whitespace!
"LIST@3..11".to_string(), "List@3..11".to_string(),
"WHITESPACE@11..12".to_string(), "Whitespace@11..12".to_string(),
"ATOM@12..14".to_string(), "Atom@12..14".to_string(),
"R_PAREN@14..15".to_string(), "RParen@14..15".to_string(),
] ]
); );
} }
@ -263,27 +262,30 @@ fn test_parser() {
/// For that, let's define AST nodes. /// For that, let's define AST nodes.
/// It'll be quite a bunch of repetitive code, so we'll use a macro. /// It'll be quite a bunch of repetitive code, so we'll use a macro.
/// For a real language, you may want to automatically generate the AST implementations with a task. /// For a real language, you may want to automatically generate the AST implementations with a task.
macro_rules! ast_node { mod ast {
($ast:ident, $kind:ident) => { use super::*;
#[derive(PartialEq, Eq, Hash)] macro_rules! ast_node {
#[repr(transparent)] ($ast:ident, $kind:ident) => {
struct $ast(SyntaxNode); #[derive(PartialEq, Eq, Hash)]
impl $ast { #[repr(transparent)]
#[allow(unused)] pub struct $ast(pub(crate) SyntaxNode);
fn cast(node: SyntaxNode) -> Option<Self> { impl $ast {
if node.kind() == $kind { #[allow(unused)]
Some(Self(node)) pub fn cast(node: SyntaxNode) -> Option<Self> {
} else { if node.kind() == SyntaxKind::$kind {
None Some(Self(node))
} else {
None
}
} }
} }
} };
}; }
}
ast_node!(Root, ROOT); ast_node!(Root, Root);
ast_node!(Atom, ATOM); ast_node!(Atom, Atom);
ast_node!(List, LIST); ast_node!(List, List);
}
// Sexp is slightly different because it can be both an atom and a list, so let's do it by hand. // Sexp is slightly different because it can be both an atom and a list, so let's do it by hand.
#[derive(PartialEq, Eq, Hash)] #[derive(PartialEq, Eq, Hash)]
@ -291,12 +293,13 @@ ast_node!(List, LIST);
struct Sexp(SyntaxNode); struct Sexp(SyntaxNode);
enum SexpKind { enum SexpKind {
Atom(Atom), Atom(ast::Atom),
List(List), List(ast::List),
} }
impl Sexp { impl Sexp {
fn cast(node: SyntaxNode) -> Option<Self> { fn cast(node: SyntaxNode) -> Option<Self> {
use ast::*;
if Atom::cast(node.clone()).is_some() || List::cast(node.clone()).is_some() { if Atom::cast(node.clone()).is_some() || List::cast(node.clone()).is_some() {
Some(Sexp(node)) Some(Sexp(node))
} else { } else {
@ -305,6 +308,7 @@ impl Sexp {
} }
fn kind(&self) -> SexpKind { fn kind(&self) -> SexpKind {
use ast::*;
Atom::cast(self.0.clone()) Atom::cast(self.0.clone())
.map(SexpKind::Atom) .map(SexpKind::Atom)
.or_else(|| List::cast(self.0.clone()).map(SexpKind::List)) .or_else(|| List::cast(self.0.clone()).map(SexpKind::List))
@ -313,7 +317,7 @@ impl Sexp {
} }
// Let's enhance AST nodes with ancillary functions and eval. // Let's enhance AST nodes with ancillary functions and eval.
impl Root { impl ast::Root {
fn sexps(&self) -> impl Iterator<Item = Sexp> + '_ { fn sexps(&self) -> impl Iterator<Item = Sexp> + '_ {
self.0.children().cloned().filter_map(Sexp::cast) self.0.children().cloned().filter_map(Sexp::cast)
} }
@ -326,7 +330,7 @@ enum Op {
Mul, Mul,
} }
impl Atom { impl ast::Atom {
fn eval(&self, resolver: &impl Resolver) -> Option<i64> { fn eval(&self, resolver: &impl Resolver) -> Option<i64> {
self.text(resolver).parse().ok() self.text(resolver).parse().ok()
} }
@ -350,7 +354,7 @@ impl Atom {
} }
} }
impl List { impl ast::List {
fn sexps(&self) -> impl Iterator<Item = Sexp> + '_ { fn sexps(&self) -> impl Iterator<Item = Sexp> + '_ {
self.0.children().cloned().filter_map(Sexp::cast) self.0.children().cloned().filter_map(Sexp::cast)
} }
@ -383,8 +387,8 @@ impl Sexp {
} }
impl<I> Parse<I> { impl<I> Parse<I> {
fn root(&self) -> Root { fn root(&self) -> ast::Root {
Root::cast(self.syntax()).unwrap() ast::Root::cast(self.syntax()).unwrap()
} }
} }
@ -412,22 +416,22 @@ fn lex(text: &str) -> VecDeque<(SyntaxKind, &str)> {
} }
fn kind(t: m_lexer::TokenKind) -> SyntaxKind { fn kind(t: m_lexer::TokenKind) -> SyntaxKind {
match t.0 { match t.0 {
0 => L_PAREN, 0 => LParen,
1 => R_PAREN, 1 => RParen,
2 => WORD, 2 => Word,
3 => WHITESPACE, 3 => Whitespace,
4 => ERROR, 4 => Error,
_ => unreachable!(), _ => unreachable!(),
} }
} }
let lexer = m_lexer::LexerBuilder::new() let lexer = m_lexer::LexerBuilder::new()
.error_token(tok(ERROR)) .error_token(tok(Error))
.tokens(&[ .tokens(&[
(tok(L_PAREN), r"\("), (tok(LParen), r"\("),
(tok(R_PAREN), r"\)"), (tok(RParen), r"\)"),
(tok(WORD), r"[^\s()]+"), (tok(Word), r"[^\s()]+"),
(tok(WHITESPACE), r"\s+"), (tok(Whitespace), r"\s+"),
]) ])
.build(); .build();