Rename two syntax types

This commit is contained in:
Laurenz 2022-11-22 14:48:08 +01:00
parent 2ce727fc95
commit b476de87b7
11 changed files with 825 additions and 821 deletions

View File

@ -11,7 +11,7 @@ use super::{
};
use crate::diag::{bail, error, At, SourceResult, StrResult, Trace, Tracepoint};
use crate::geom::{Abs, Angle, Em, Fr, Ratio};
use crate::syntax::ast::TypedNode;
use crate::syntax::ast::AstNode;
use crate::syntax::{ast, SourceId, Span, Spanned, Unit};
use crate::util::{format_eco, EcoString};
use crate::World;

View File

@ -8,7 +8,7 @@ use super::{
Args, Eval, Flow, Node, NodeId, Route, Scope, Scopes, Selector, StyleMap, Value, Vm,
};
use crate::diag::{bail, SourceResult, StrResult};
use crate::syntax::ast::{self, Expr, TypedNode};
use crate::syntax::ast::{self, AstNode, Expr};
use crate::syntax::{SourceId, Span, SyntaxNode};
use crate::util::EcoString;
use crate::World;

View File

@ -5,11 +5,11 @@
use std::num::NonZeroUsize;
use std::ops::Deref;
use super::{NodeKind, RawFields, Span, SyntaxNode, Unit};
use super::{RawFields, Span, SyntaxKind, SyntaxNode, Unit};
use crate::util::EcoString;
/// A typed AST node.
pub trait TypedNode: Sized {
pub trait AstNode: Sized {
/// Convert a node into its typed variant.
fn from_untyped(node: &SyntaxNode) -> Option<Self>;
@ -24,7 +24,7 @@ pub trait TypedNode: Sized {
macro_rules! node {
($(#[$attr:meta])* $name:ident) => {
node!{ $(#[$attr])* $name: NodeKind::$name { .. } }
node!{ $(#[$attr])* $name: SyntaxKind::$name { .. } }
};
($(#[$attr:meta])* $name:ident: $variants:pat) => {
#[derive(Debug, Clone, PartialEq, Hash)]
@ -32,7 +32,7 @@ macro_rules! node {
$(#[$attr])*
pub struct $name(SyntaxNode);
impl TypedNode for $name {
impl AstNode for $name {
fn from_untyped(node: &SyntaxNode) -> Option<Self> {
if matches!(node.kind(), $variants) {
Some(Self(node.clone()))
@ -62,7 +62,8 @@ impl Markup {
.filter(move |node| {
// Ignore linebreak directly after statements without semicolons.
let kind = node.kind();
let keep = !was_stmt || !matches!(kind, NodeKind::Space { newlines: 1 });
let keep =
!was_stmt || !matches!(kind, SyntaxKind::Space { newlines: 1 });
was_stmt = kind.is_stmt();
keep
})
@ -112,26 +113,26 @@ pub enum MarkupNode {
Expr(Expr),
}
impl TypedNode for MarkupNode {
impl AstNode for MarkupNode {
fn from_untyped(node: &SyntaxNode) -> Option<Self> {
match node.kind() {
NodeKind::Space { .. } => node.cast().map(Self::Space),
NodeKind::Linebreak => node.cast().map(Self::Linebreak),
NodeKind::Text(_) => node.cast().map(Self::Text),
NodeKind::Escape(_) => node.cast().map(Self::Escape),
NodeKind::Shorthand(_) => node.cast().map(Self::Shorthand),
NodeKind::SmartQuote { .. } => node.cast().map(Self::SmartQuote),
NodeKind::Strong => node.cast().map(Self::Strong),
NodeKind::Emph => node.cast().map(Self::Emph),
NodeKind::Raw(_) => node.cast().map(Self::Raw),
NodeKind::Link(_) => node.cast().map(Self::Link),
NodeKind::Label(_) => node.cast().map(Self::Label),
NodeKind::Ref(_) => node.cast().map(Self::Ref),
NodeKind::Heading => node.cast().map(Self::Heading),
NodeKind::ListItem => node.cast().map(Self::List),
NodeKind::EnumItem => node.cast().map(Self::Enum),
NodeKind::DescItem => node.cast().map(Self::Desc),
NodeKind::Math => node.cast().map(Self::Math),
SyntaxKind::Space { .. } => node.cast().map(Self::Space),
SyntaxKind::Linebreak => node.cast().map(Self::Linebreak),
SyntaxKind::Text(_) => node.cast().map(Self::Text),
SyntaxKind::Escape(_) => node.cast().map(Self::Escape),
SyntaxKind::Shorthand(_) => node.cast().map(Self::Shorthand),
SyntaxKind::SmartQuote { .. } => node.cast().map(Self::SmartQuote),
SyntaxKind::Strong => node.cast().map(Self::Strong),
SyntaxKind::Emph => node.cast().map(Self::Emph),
SyntaxKind::Raw(_) => node.cast().map(Self::Raw),
SyntaxKind::Link(_) => node.cast().map(Self::Link),
SyntaxKind::Label(_) => node.cast().map(Self::Label),
SyntaxKind::Ref(_) => node.cast().map(Self::Ref),
SyntaxKind::Heading => node.cast().map(Self::Heading),
SyntaxKind::ListItem => node.cast().map(Self::List),
SyntaxKind::EnumItem => node.cast().map(Self::Enum),
SyntaxKind::DescItem => node.cast().map(Self::Desc),
SyntaxKind::Math => node.cast().map(Self::Math),
_ => node.cast().map(Self::Expr),
}
}
@ -169,7 +170,7 @@ impl Space {
/// Get the number of newlines.
pub fn newlines(&self) -> usize {
match self.0.kind() {
&NodeKind::Space { newlines } => newlines,
&SyntaxKind::Space { newlines } => newlines,
_ => panic!("space is of wrong kind"),
}
}
@ -189,7 +190,7 @@ impl Text {
/// Get the text.
pub fn get(&self) -> &EcoString {
match self.0.kind() {
NodeKind::Text(v) => v,
SyntaxKind::Text(v) => v,
_ => panic!("text is of wrong kind"),
}
}
@ -204,7 +205,7 @@ impl Escape {
/// Get the escaped character.
pub fn get(&self) -> char {
match self.0.kind() {
&NodeKind::Escape(v) => v,
&SyntaxKind::Escape(v) => v,
_ => panic!("escape is of wrong kind"),
}
}
@ -220,7 +221,7 @@ impl Shorthand {
/// Get the shorthanded character.
pub fn get(&self) -> char {
match self.0.kind() {
&NodeKind::Shorthand(v) => v,
&SyntaxKind::Shorthand(v) => v,
_ => panic!("shorthand is of wrong kind"),
}
}
@ -235,7 +236,7 @@ impl SmartQuote {
/// Whether this is a double quote.
pub fn double(&self) -> bool {
match self.0.kind() {
&NodeKind::SmartQuote { double } => double,
&SyntaxKind::SmartQuote { double } => double,
_ => panic!("smart quote is of wrong kind"),
}
}
@ -291,7 +292,7 @@ impl Raw {
/// The raw fields.
fn get(&self) -> &RawFields {
match self.0.kind() {
NodeKind::Raw(v) => v.as_ref(),
SyntaxKind::Raw(v) => v.as_ref(),
_ => panic!("raw is of wrong kind"),
}
}
@ -306,7 +307,7 @@ impl Link {
/// Get the URL.
pub fn url(&self) -> &EcoString {
match self.0.kind() {
NodeKind::Link(url) => url,
SyntaxKind::Link(url) => url,
_ => panic!("link is of wrong kind"),
}
}
@ -321,7 +322,7 @@ impl Label {
/// Get the label.
pub fn get(&self) -> &EcoString {
match self.0.kind() {
NodeKind::Label(v) => v,
SyntaxKind::Label(v) => v,
_ => panic!("label is of wrong kind"),
}
}
@ -336,7 +337,7 @@ impl Ref {
/// Get the target.
pub fn get(&self) -> &EcoString {
match self.0.kind() {
NodeKind::Ref(v) => v,
SyntaxKind::Ref(v) => v,
_ => panic!("reference is of wrong kind"),
}
}
@ -357,7 +358,7 @@ impl Heading {
pub fn level(&self) -> NonZeroUsize {
self.0
.children()
.filter(|n| n.kind() == &NodeKind::Eq)
.filter(|n| n.kind() == &SyntaxKind::Eq)
.count()
.try_into()
.expect("heading is missing equals sign")
@ -385,7 +386,7 @@ impl EnumItem {
/// The explicit numbering, if any: `23.`.
pub fn number(&self) -> Option<usize> {
self.0.children().find_map(|node| match node.kind() {
NodeKind::EnumNumbering(num) => Some(*num),
SyntaxKind::EnumNumbering(num) => Some(*num),
_ => None,
})
}
@ -458,17 +459,17 @@ pub enum MathNode {
Expr(Expr),
}
impl TypedNode for MathNode {
impl AstNode for MathNode {
fn from_untyped(node: &SyntaxNode) -> Option<Self> {
match node.kind() {
NodeKind::Space { .. } => node.cast().map(Self::Space),
NodeKind::Linebreak => node.cast().map(Self::Linebreak),
NodeKind::Escape(_) => node.cast().map(Self::Escape),
NodeKind::Atom(_) => node.cast().map(Self::Atom),
NodeKind::Script => node.cast().map(Self::Script),
NodeKind::Frac => node.cast().map(Self::Frac),
NodeKind::Align => node.cast().map(Self::Align),
NodeKind::Math => node.cast().map(Self::Group),
SyntaxKind::Space { .. } => node.cast().map(Self::Space),
SyntaxKind::Linebreak => node.cast().map(Self::Linebreak),
SyntaxKind::Escape(_) => node.cast().map(Self::Escape),
SyntaxKind::Atom(_) => node.cast().map(Self::Atom),
SyntaxKind::Script => node.cast().map(Self::Script),
SyntaxKind::Frac => node.cast().map(Self::Frac),
SyntaxKind::Align => node.cast().map(Self::Align),
SyntaxKind::Math => node.cast().map(Self::Group),
_ => node.cast().map(Self::Expr),
}
}
@ -497,7 +498,7 @@ impl Atom {
/// Get the atom's text.
pub fn get(&self) -> &EcoString {
match self.0.kind() {
NodeKind::Atom(v) => v,
SyntaxKind::Atom(v) => v,
_ => panic!("atom is of wrong kind"),
}
}
@ -518,7 +519,7 @@ impl Script {
pub fn sub(&self) -> Option<MathNode> {
self.0
.children()
.skip_while(|node| !matches!(node.kind(), NodeKind::Underscore))
.skip_while(|node| !matches!(node.kind(), SyntaxKind::Underscore))
.nth(1)
.map(|node| node.cast().expect("script node has invalid subscript"))
}
@ -527,7 +528,7 @@ impl Script {
pub fn sup(&self) -> Option<MathNode> {
self.0
.children()
.skip_while(|node| !matches!(node.kind(), NodeKind::Hat))
.skip_while(|node| !matches!(node.kind(), SyntaxKind::Hat))
.nth(1)
.map(|node| node.cast().expect("script node has invalid superscript"))
}
@ -558,7 +559,7 @@ node! {
impl Align {
/// The number of ampersands.
pub fn count(&self) -> usize {
self.0.children().filter(|n| n.kind() == &NodeKind::Amp).count()
self.0.children().filter(|n| n.kind() == &SyntaxKind::Amp).count()
}
}
@ -615,32 +616,32 @@ pub enum Expr {
Return(FuncReturn),
}
impl TypedNode for Expr {
impl AstNode for Expr {
fn from_untyped(node: &SyntaxNode) -> Option<Self> {
match node.kind() {
NodeKind::Ident(_) => node.cast().map(Self::Ident),
NodeKind::CodeBlock => node.cast().map(Self::Code),
NodeKind::ContentBlock => node.cast().map(Self::Content),
NodeKind::Parenthesized => node.cast().map(Self::Parenthesized),
NodeKind::Array => node.cast().map(Self::Array),
NodeKind::Dict => node.cast().map(Self::Dict),
NodeKind::Unary => node.cast().map(Self::Unary),
NodeKind::Binary => node.cast().map(Self::Binary),
NodeKind::FieldAccess => node.cast().map(Self::FieldAccess),
NodeKind::FuncCall => node.cast().map(Self::FuncCall),
NodeKind::MethodCall => node.cast().map(Self::MethodCall),
NodeKind::Closure => node.cast().map(Self::Closure),
NodeKind::LetBinding => node.cast().map(Self::Let),
NodeKind::SetRule => node.cast().map(Self::Set),
NodeKind::ShowRule => node.cast().map(Self::Show),
NodeKind::Conditional => node.cast().map(Self::Conditional),
NodeKind::WhileLoop => node.cast().map(Self::While),
NodeKind::ForLoop => node.cast().map(Self::For),
NodeKind::ModuleImport => node.cast().map(Self::Import),
NodeKind::ModuleInclude => node.cast().map(Self::Include),
NodeKind::LoopBreak => node.cast().map(Self::Break),
NodeKind::LoopContinue => node.cast().map(Self::Continue),
NodeKind::FuncReturn => node.cast().map(Self::Return),
SyntaxKind::Ident(_) => node.cast().map(Self::Ident),
SyntaxKind::CodeBlock => node.cast().map(Self::Code),
SyntaxKind::ContentBlock => node.cast().map(Self::Content),
SyntaxKind::Parenthesized => node.cast().map(Self::Parenthesized),
SyntaxKind::Array => node.cast().map(Self::Array),
SyntaxKind::Dict => node.cast().map(Self::Dict),
SyntaxKind::Unary => node.cast().map(Self::Unary),
SyntaxKind::Binary => node.cast().map(Self::Binary),
SyntaxKind::FieldAccess => node.cast().map(Self::FieldAccess),
SyntaxKind::FuncCall => node.cast().map(Self::FuncCall),
SyntaxKind::MethodCall => node.cast().map(Self::MethodCall),
SyntaxKind::Closure => node.cast().map(Self::Closure),
SyntaxKind::LetBinding => node.cast().map(Self::Let),
SyntaxKind::SetRule => node.cast().map(Self::Set),
SyntaxKind::ShowRule => node.cast().map(Self::Show),
SyntaxKind::Conditional => node.cast().map(Self::Conditional),
SyntaxKind::WhileLoop => node.cast().map(Self::While),
SyntaxKind::ForLoop => node.cast().map(Self::For),
SyntaxKind::ModuleImport => node.cast().map(Self::Import),
SyntaxKind::ModuleInclude => node.cast().map(Self::Include),
SyntaxKind::LoopBreak => node.cast().map(Self::Break),
SyntaxKind::LoopContinue => node.cast().map(Self::Continue),
SyntaxKind::FuncReturn => node.cast().map(Self::Return),
_ => node.cast().map(Self::Lit),
}
}
@ -696,26 +697,26 @@ impl Expr {
node! {
/// A literal: `1`, `true`, ...
Lit: NodeKind::None
| NodeKind::Auto
| NodeKind::Bool(_)
| NodeKind::Int(_)
| NodeKind::Float(_)
| NodeKind::Numeric(_, _)
| NodeKind::Str(_)
Lit: SyntaxKind::None
| SyntaxKind::Auto
| SyntaxKind::Bool(_)
| SyntaxKind::Int(_)
| SyntaxKind::Float(_)
| SyntaxKind::Numeric(_, _)
| SyntaxKind::Str(_)
}
impl Lit {
/// The kind of literal.
pub fn kind(&self) -> LitKind {
match *self.0.kind() {
NodeKind::None => LitKind::None,
NodeKind::Auto => LitKind::Auto,
NodeKind::Bool(v) => LitKind::Bool(v),
NodeKind::Int(v) => LitKind::Int(v),
NodeKind::Float(v) => LitKind::Float(v),
NodeKind::Numeric(v, unit) => LitKind::Numeric(v, unit),
NodeKind::Str(ref v) => LitKind::Str(v.clone()),
SyntaxKind::None => LitKind::None,
SyntaxKind::Auto => LitKind::Auto,
SyntaxKind::Bool(v) => LitKind::Bool(v),
SyntaxKind::Int(v) => LitKind::Int(v),
SyntaxKind::Float(v) => LitKind::Float(v),
SyntaxKind::Numeric(v, unit) => LitKind::Numeric(v, unit),
SyntaxKind::Str(ref v) => LitKind::Str(v.clone()),
_ => panic!("literal is of wrong kind"),
}
}
@ -799,10 +800,10 @@ pub enum ArrayItem {
Spread(Expr),
}
impl TypedNode for ArrayItem {
impl AstNode for ArrayItem {
fn from_untyped(node: &SyntaxNode) -> Option<Self> {
match node.kind() {
NodeKind::Spread => node.cast_first_child().map(Self::Spread),
SyntaxKind::Spread => node.cast_first_child().map(Self::Spread),
_ => node.cast().map(Self::Pos),
}
}
@ -838,12 +839,12 @@ pub enum DictItem {
Spread(Expr),
}
impl TypedNode for DictItem {
impl AstNode for DictItem {
fn from_untyped(node: &SyntaxNode) -> Option<Self> {
match node.kind() {
NodeKind::Named => node.cast().map(Self::Named),
NodeKind::Keyed => node.cast().map(Self::Keyed),
NodeKind::Spread => node.cast_first_child().map(Self::Spread),
SyntaxKind::Named => node.cast().map(Self::Named),
SyntaxKind::Keyed => node.cast().map(Self::Keyed),
SyntaxKind::Spread => node.cast_first_child().map(Self::Spread),
_ => None,
}
}
@ -885,7 +886,7 @@ impl Keyed {
self.0
.children()
.find_map(|node| match node.kind() {
NodeKind::Str(key) => Some(key.clone()),
SyntaxKind::Str(key) => Some(key.clone()),
_ => None,
})
.expect("keyed pair is missing key")
@ -930,11 +931,11 @@ pub enum UnOp {
impl UnOp {
/// Try to convert the token into a unary operation.
pub fn from_token(token: &NodeKind) -> Option<Self> {
pub fn from_token(token: &SyntaxKind) -> Option<Self> {
Some(match token {
NodeKind::Plus => Self::Pos,
NodeKind::Minus => Self::Neg,
NodeKind::Not => Self::Not,
SyntaxKind::Plus => Self::Pos,
SyntaxKind::Minus => Self::Neg,
SyntaxKind::Not => Self::Not,
_ => return None,
})
}
@ -969,11 +970,11 @@ impl Binary {
self.0
.children()
.find_map(|node| match node.kind() {
NodeKind::Not => {
SyntaxKind::Not => {
not = true;
None
}
NodeKind::In if not => Some(BinOp::NotIn),
SyntaxKind::In if not => Some(BinOp::NotIn),
_ => BinOp::from_token(node.kind()),
})
.expect("binary operation is missing operator")
@ -1039,26 +1040,26 @@ pub enum BinOp {
impl BinOp {
/// Try to convert the token into a binary operation.
pub fn from_token(token: &NodeKind) -> Option<Self> {
pub fn from_token(token: &SyntaxKind) -> Option<Self> {
Some(match token {
NodeKind::Plus => Self::Add,
NodeKind::Minus => Self::Sub,
NodeKind::Star => Self::Mul,
NodeKind::Slash => Self::Div,
NodeKind::And => Self::And,
NodeKind::Or => Self::Or,
NodeKind::EqEq => Self::Eq,
NodeKind::ExclEq => Self::Neq,
NodeKind::Lt => Self::Lt,
NodeKind::LtEq => Self::Leq,
NodeKind::Gt => Self::Gt,
NodeKind::GtEq => Self::Geq,
NodeKind::Eq => Self::Assign,
NodeKind::In => Self::In,
NodeKind::PlusEq => Self::AddAssign,
NodeKind::HyphEq => Self::SubAssign,
NodeKind::StarEq => Self::MulAssign,
NodeKind::SlashEq => Self::DivAssign,
SyntaxKind::Plus => Self::Add,
SyntaxKind::Minus => Self::Sub,
SyntaxKind::Star => Self::Mul,
SyntaxKind::Slash => Self::Div,
SyntaxKind::And => Self::And,
SyntaxKind::Or => Self::Or,
SyntaxKind::EqEq => Self::Eq,
SyntaxKind::ExclEq => Self::Neq,
SyntaxKind::Lt => Self::Lt,
SyntaxKind::LtEq => Self::Leq,
SyntaxKind::Gt => Self::Gt,
SyntaxKind::GtEq => Self::Geq,
SyntaxKind::Eq => Self::Assign,
SyntaxKind::In => Self::In,
SyntaxKind::PlusEq => Self::AddAssign,
SyntaxKind::HyphEq => Self::SubAssign,
SyntaxKind::StarEq => Self::MulAssign,
SyntaxKind::SlashEq => Self::DivAssign,
_ => return None,
})
}
@ -1231,11 +1232,11 @@ pub enum Arg {
Spread(Expr),
}
impl TypedNode for Arg {
impl AstNode for Arg {
fn from_untyped(node: &SyntaxNode) -> Option<Self> {
match node.kind() {
NodeKind::Named => node.cast().map(Self::Named),
NodeKind::Spread => node.cast_first_child().map(Self::Spread),
SyntaxKind::Named => node.cast().map(Self::Named),
SyntaxKind::Spread => node.cast_first_child().map(Self::Spread),
_ => node.cast().map(Self::Pos),
}
}
@ -1266,7 +1267,7 @@ impl Closure {
pub fn params(&self) -> impl DoubleEndedIterator<Item = Param> + '_ {
self.0
.children()
.find(|x| x.kind() == &NodeKind::Params)
.find(|x| x.kind() == &SyntaxKind::Params)
.expect("closure is missing parameter list")
.children()
.filter_map(SyntaxNode::cast)
@ -1289,12 +1290,12 @@ pub enum Param {
Sink(Ident),
}
impl TypedNode for Param {
impl AstNode for Param {
fn from_untyped(node: &SyntaxNode) -> Option<Self> {
match node.kind() {
NodeKind::Ident(_) => node.cast().map(Self::Pos),
NodeKind::Named => node.cast().map(Self::Named),
NodeKind::Spread => node.cast_first_child().map(Self::Sink),
SyntaxKind::Ident(_) => node.cast().map(Self::Pos),
SyntaxKind::Named => node.cast().map(Self::Named),
SyntaxKind::Spread => node.cast_first_child().map(Self::Sink),
_ => None,
}
}
@ -1357,7 +1358,7 @@ impl SetRule {
pub fn condition(&self) -> Option<Expr> {
self.0
.children()
.skip_while(|child| child.kind() != &NodeKind::If)
.skip_while(|child| child.kind() != &SyntaxKind::If)
.find_map(SyntaxNode::cast)
}
}
@ -1373,7 +1374,7 @@ impl ShowRule {
self.0
.children()
.rev()
.skip_while(|child| child.kind() != &NodeKind::Colon)
.skip_while(|child| child.kind() != &SyntaxKind::Colon)
.find_map(SyntaxNode::cast)
}
@ -1482,8 +1483,8 @@ impl ModuleImport {
self.0
.children()
.find_map(|node| match node.kind() {
NodeKind::Star => Some(Imports::Wildcard),
NodeKind::ImportItems => {
SyntaxKind::Star => Some(Imports::Wildcard),
SyntaxKind::ImportItems => {
let items = node.children().filter_map(SyntaxNode::cast).collect();
Some(Imports::Items(items))
}
@ -1550,7 +1551,7 @@ impl Ident {
/// Get the identifier.
pub fn get(&self) -> &EcoString {
match self.0.kind() {
NodeKind::Ident(id) => id,
SyntaxKind::Ident(id) => id,
_ => panic!("identifier is of wrong kind"),
}
}
@ -1558,7 +1559,7 @@ impl Ident {
/// Take out the container identifier.
pub fn take(self) -> EcoString {
match self.0.take() {
NodeKind::Ident(id) => id,
SyntaxKind::Ident(id) => id,
_ => panic!("identifier is of wrong kind"),
}
}

View File

@ -6,7 +6,7 @@ use std::ops::Range;
use syntect::highlighting::{Color, FontStyle, Highlighter, Style, Theme};
use syntect::parsing::Scope;
use super::{parse, NodeKind, SyntaxNode};
use super::{parse, SyntaxKind, SyntaxNode};
/// Highlight source text into a standalone HTML document.
pub fn highlight_html(text: &str, theme: &Theme) -> String {
@ -194,170 +194,170 @@ impl Category {
i: usize,
) -> Option<Category> {
match child.kind() {
NodeKind::LineComment => Some(Category::Comment),
NodeKind::BlockComment => Some(Category::Comment),
NodeKind::Space { .. } => None,
SyntaxKind::LineComment => Some(Category::Comment),
SyntaxKind::BlockComment => Some(Category::Comment),
SyntaxKind::Space { .. } => None,
NodeKind::LeftBrace => Some(Category::Bracket),
NodeKind::RightBrace => Some(Category::Bracket),
NodeKind::LeftBracket => Some(Category::Bracket),
NodeKind::RightBracket => Some(Category::Bracket),
NodeKind::LeftParen => Some(Category::Bracket),
NodeKind::RightParen => Some(Category::Bracket),
NodeKind::Comma => Some(Category::Punctuation),
NodeKind::Semicolon => Some(Category::Punctuation),
NodeKind::Colon => Some(Category::Punctuation),
NodeKind::Star => match parent.kind() {
NodeKind::Strong => None,
SyntaxKind::LeftBrace => Some(Category::Bracket),
SyntaxKind::RightBrace => Some(Category::Bracket),
SyntaxKind::LeftBracket => Some(Category::Bracket),
SyntaxKind::RightBracket => Some(Category::Bracket),
SyntaxKind::LeftParen => Some(Category::Bracket),
SyntaxKind::RightParen => Some(Category::Bracket),
SyntaxKind::Comma => Some(Category::Punctuation),
SyntaxKind::Semicolon => Some(Category::Punctuation),
SyntaxKind::Colon => Some(Category::Punctuation),
SyntaxKind::Star => match parent.kind() {
SyntaxKind::Strong => None,
_ => Some(Category::Operator),
},
NodeKind::Underscore => match parent.kind() {
NodeKind::Script => Some(Category::MathOperator),
SyntaxKind::Underscore => match parent.kind() {
SyntaxKind::Script => Some(Category::MathOperator),
_ => None,
},
NodeKind::Dollar => Some(Category::MathDelimiter),
NodeKind::Plus => Some(match parent.kind() {
NodeKind::EnumItem => Category::ListMarker,
SyntaxKind::Dollar => Some(Category::MathDelimiter),
SyntaxKind::Plus => Some(match parent.kind() {
SyntaxKind::EnumItem => Category::ListMarker,
_ => Category::Operator,
}),
NodeKind::Minus => Some(match parent.kind() {
NodeKind::ListItem => Category::ListMarker,
SyntaxKind::Minus => Some(match parent.kind() {
SyntaxKind::ListItem => Category::ListMarker,
_ => Category::Operator,
}),
NodeKind::Slash => Some(match parent.kind() {
NodeKind::DescItem => Category::ListMarker,
NodeKind::Frac => Category::MathOperator,
SyntaxKind::Slash => Some(match parent.kind() {
SyntaxKind::DescItem => Category::ListMarker,
SyntaxKind::Frac => Category::MathOperator,
_ => Category::Operator,
}),
NodeKind::Hat => Some(Category::MathOperator),
NodeKind::Amp => Some(Category::MathOperator),
NodeKind::Dot => Some(Category::Punctuation),
NodeKind::Eq => match parent.kind() {
NodeKind::Heading => None,
SyntaxKind::Hat => Some(Category::MathOperator),
SyntaxKind::Amp => Some(Category::MathOperator),
SyntaxKind::Dot => Some(Category::Punctuation),
SyntaxKind::Eq => match parent.kind() {
SyntaxKind::Heading => None,
_ => Some(Category::Operator),
},
NodeKind::EqEq => Some(Category::Operator),
NodeKind::ExclEq => Some(Category::Operator),
NodeKind::Lt => Some(Category::Operator),
NodeKind::LtEq => Some(Category::Operator),
NodeKind::Gt => Some(Category::Operator),
NodeKind::GtEq => Some(Category::Operator),
NodeKind::PlusEq => Some(Category::Operator),
NodeKind::HyphEq => Some(Category::Operator),
NodeKind::StarEq => Some(Category::Operator),
NodeKind::SlashEq => Some(Category::Operator),
NodeKind::Dots => Some(Category::Operator),
NodeKind::Arrow => Some(Category::Operator),
SyntaxKind::EqEq => Some(Category::Operator),
SyntaxKind::ExclEq => Some(Category::Operator),
SyntaxKind::Lt => Some(Category::Operator),
SyntaxKind::LtEq => Some(Category::Operator),
SyntaxKind::Gt => Some(Category::Operator),
SyntaxKind::GtEq => Some(Category::Operator),
SyntaxKind::PlusEq => Some(Category::Operator),
SyntaxKind::HyphEq => Some(Category::Operator),
SyntaxKind::StarEq => Some(Category::Operator),
SyntaxKind::SlashEq => Some(Category::Operator),
SyntaxKind::Dots => Some(Category::Operator),
SyntaxKind::Arrow => Some(Category::Operator),
NodeKind::Not => Some(Category::Keyword),
NodeKind::And => Some(Category::Keyword),
NodeKind::Or => Some(Category::Keyword),
NodeKind::None => Some(Category::KeywordLiteral),
NodeKind::Auto => Some(Category::KeywordLiteral),
NodeKind::Let => Some(Category::Keyword),
NodeKind::Set => Some(Category::Keyword),
NodeKind::Show => Some(Category::Keyword),
NodeKind::If => Some(Category::Keyword),
NodeKind::Else => Some(Category::Keyword),
NodeKind::For => Some(Category::Keyword),
NodeKind::In => Some(Category::Keyword),
NodeKind::While => Some(Category::Keyword),
NodeKind::Break => Some(Category::Keyword),
NodeKind::Continue => Some(Category::Keyword),
NodeKind::Return => Some(Category::Keyword),
NodeKind::Import => Some(Category::Keyword),
NodeKind::Include => Some(Category::Keyword),
NodeKind::From => Some(Category::Keyword),
SyntaxKind::Not => Some(Category::Keyword),
SyntaxKind::And => Some(Category::Keyword),
SyntaxKind::Or => Some(Category::Keyword),
SyntaxKind::None => Some(Category::KeywordLiteral),
SyntaxKind::Auto => Some(Category::KeywordLiteral),
SyntaxKind::Let => Some(Category::Keyword),
SyntaxKind::Set => Some(Category::Keyword),
SyntaxKind::Show => Some(Category::Keyword),
SyntaxKind::If => Some(Category::Keyword),
SyntaxKind::Else => Some(Category::Keyword),
SyntaxKind::For => Some(Category::Keyword),
SyntaxKind::In => Some(Category::Keyword),
SyntaxKind::While => Some(Category::Keyword),
SyntaxKind::Break => Some(Category::Keyword),
SyntaxKind::Continue => Some(Category::Keyword),
SyntaxKind::Return => Some(Category::Keyword),
SyntaxKind::Import => Some(Category::Keyword),
SyntaxKind::Include => Some(Category::Keyword),
SyntaxKind::From => Some(Category::Keyword),
NodeKind::Markup { .. } => match parent.kind() {
NodeKind::DescItem
SyntaxKind::Markup { .. } => match parent.kind() {
SyntaxKind::DescItem
if parent
.children()
.take_while(|child| child.kind() != &NodeKind::Colon)
.find(|c| matches!(c.kind(), NodeKind::Markup { .. }))
.take_while(|child| child.kind() != &SyntaxKind::Colon)
.find(|c| matches!(c.kind(), SyntaxKind::Markup { .. }))
.map_or(false, |ident| std::ptr::eq(ident, child)) =>
{
Some(Category::ListTerm)
}
_ => None,
},
NodeKind::Text(_) => None,
NodeKind::Linebreak => Some(Category::Escape),
NodeKind::Escape(_) => Some(Category::Escape),
NodeKind::Shorthand(_) => Some(Category::Shorthand),
NodeKind::SmartQuote { .. } => Some(Category::SmartQuote),
NodeKind::Strong => Some(Category::Strong),
NodeKind::Emph => Some(Category::Emph),
NodeKind::Raw(_) => Some(Category::Raw),
NodeKind::Link(_) => Some(Category::Link),
NodeKind::Label(_) => Some(Category::Label),
NodeKind::Ref(_) => Some(Category::Ref),
NodeKind::Heading => Some(Category::Heading),
NodeKind::ListItem => Some(Category::ListItem),
NodeKind::EnumItem => Some(Category::ListItem),
NodeKind::EnumNumbering(_) => Some(Category::ListMarker),
NodeKind::DescItem => Some(Category::ListItem),
NodeKind::Math => Some(Category::Math),
NodeKind::Atom(_) => None,
NodeKind::Script => None,
NodeKind::Frac => None,
NodeKind::Align => None,
SyntaxKind::Text(_) => None,
SyntaxKind::Linebreak => Some(Category::Escape),
SyntaxKind::Escape(_) => Some(Category::Escape),
SyntaxKind::Shorthand(_) => Some(Category::Shorthand),
SyntaxKind::SmartQuote { .. } => Some(Category::SmartQuote),
SyntaxKind::Strong => Some(Category::Strong),
SyntaxKind::Emph => Some(Category::Emph),
SyntaxKind::Raw(_) => Some(Category::Raw),
SyntaxKind::Link(_) => Some(Category::Link),
SyntaxKind::Label(_) => Some(Category::Label),
SyntaxKind::Ref(_) => Some(Category::Ref),
SyntaxKind::Heading => Some(Category::Heading),
SyntaxKind::ListItem => Some(Category::ListItem),
SyntaxKind::EnumItem => Some(Category::ListItem),
SyntaxKind::EnumNumbering(_) => Some(Category::ListMarker),
SyntaxKind::DescItem => Some(Category::ListItem),
SyntaxKind::Math => Some(Category::Math),
SyntaxKind::Atom(_) => None,
SyntaxKind::Script => None,
SyntaxKind::Frac => None,
SyntaxKind::Align => None,
NodeKind::Ident(_) => match parent.kind() {
NodeKind::Markup { .. } => Some(Category::Interpolated),
NodeKind::Math => Some(Category::Interpolated),
NodeKind::FuncCall => Some(Category::Function),
NodeKind::MethodCall if i > 0 => Some(Category::Function),
NodeKind::Closure if i == 0 => Some(Category::Function),
NodeKind::SetRule => Some(Category::Function),
NodeKind::ShowRule
SyntaxKind::Ident(_) => match parent.kind() {
SyntaxKind::Markup { .. } => Some(Category::Interpolated),
SyntaxKind::Math => Some(Category::Interpolated),
SyntaxKind::FuncCall => Some(Category::Function),
SyntaxKind::MethodCall if i > 0 => Some(Category::Function),
SyntaxKind::Closure if i == 0 => Some(Category::Function),
SyntaxKind::SetRule => Some(Category::Function),
SyntaxKind::ShowRule
if parent
.children()
.rev()
.skip_while(|child| child.kind() != &NodeKind::Colon)
.find(|c| matches!(c.kind(), NodeKind::Ident(_)))
.skip_while(|child| child.kind() != &SyntaxKind::Colon)
.find(|c| matches!(c.kind(), SyntaxKind::Ident(_)))
.map_or(false, |ident| std::ptr::eq(ident, child)) =>
{
Some(Category::Function)
}
_ => None,
},
NodeKind::Bool(_) => Some(Category::KeywordLiteral),
NodeKind::Int(_) => Some(Category::Number),
NodeKind::Float(_) => Some(Category::Number),
NodeKind::Numeric(_, _) => Some(Category::Number),
NodeKind::Str(_) => Some(Category::String),
NodeKind::CodeBlock => None,
NodeKind::ContentBlock => None,
NodeKind::Parenthesized => None,
NodeKind::Array => None,
NodeKind::Dict => None,
NodeKind::Named => None,
NodeKind::Keyed => None,
NodeKind::Unary => None,
NodeKind::Binary => None,
NodeKind::FieldAccess => None,
NodeKind::FuncCall => None,
NodeKind::MethodCall => None,
NodeKind::Args => None,
NodeKind::Spread => None,
NodeKind::Closure => None,
NodeKind::Params => None,
NodeKind::LetBinding => None,
NodeKind::SetRule => None,
NodeKind::ShowRule => None,
NodeKind::Conditional => None,
NodeKind::WhileLoop => None,
NodeKind::ForLoop => None,
NodeKind::ForPattern => None,
NodeKind::ModuleImport => None,
NodeKind::ImportItems => None,
NodeKind::ModuleInclude => None,
NodeKind::LoopBreak => None,
NodeKind::LoopContinue => None,
NodeKind::FuncReturn => None,
SyntaxKind::Bool(_) => Some(Category::KeywordLiteral),
SyntaxKind::Int(_) => Some(Category::Number),
SyntaxKind::Float(_) => Some(Category::Number),
SyntaxKind::Numeric(_, _) => Some(Category::Number),
SyntaxKind::Str(_) => Some(Category::String),
SyntaxKind::CodeBlock => None,
SyntaxKind::ContentBlock => None,
SyntaxKind::Parenthesized => None,
SyntaxKind::Array => None,
SyntaxKind::Dict => None,
SyntaxKind::Named => None,
SyntaxKind::Keyed => None,
SyntaxKind::Unary => None,
SyntaxKind::Binary => None,
SyntaxKind::FieldAccess => None,
SyntaxKind::FuncCall => None,
SyntaxKind::MethodCall => None,
SyntaxKind::Args => None,
SyntaxKind::Spread => None,
SyntaxKind::Closure => None,
SyntaxKind::Params => None,
SyntaxKind::LetBinding => None,
SyntaxKind::SetRule => None,
SyntaxKind::ShowRule => None,
SyntaxKind::Conditional => None,
SyntaxKind::WhileLoop => None,
SyntaxKind::ForLoop => None,
SyntaxKind::ForPattern => None,
SyntaxKind::ModuleImport => None,
SyntaxKind::ImportItems => None,
SyntaxKind::ModuleInclude => None,
SyntaxKind::LoopBreak => None,
SyntaxKind::LoopContinue => None,
SyntaxKind::FuncReturn => None,
NodeKind::Error(_, _) => Some(Category::Error),
SyntaxKind::Error(_, _) => Some(Category::Error),
}
}

View File

@ -2,7 +2,7 @@ use std::ops::Range;
use super::{
is_newline, parse, reparse_code_block, reparse_content_block,
reparse_markup_elements, NodeKind, Span, SyntaxNode,
reparse_markup_elements, Span, SyntaxKind, SyntaxNode,
};
/// Refresh the given syntax node with as little parsing as possible.
@ -36,7 +36,7 @@ fn try_reparse(
outermost: bool,
safe_to_replace: bool,
) -> Option<Range<usize>> {
let is_markup = matches!(node.kind(), NodeKind::Markup { .. });
let is_markup = matches!(node.kind(), SyntaxKind::Markup { .. });
let original_count = node.children().len();
let original_offset = offset;
@ -78,7 +78,7 @@ fn try_reparse(
} else {
// Update compulsary state of `ahead_nontrivia`.
if let Some(ahead_nontrivia) = ahead.as_mut() {
if let NodeKind::Space { newlines: (1..) } = child.kind() {
if let SyntaxKind::Space { newlines: (1..) } = child.kind() {
ahead_nontrivia.newline();
}
}
@ -87,8 +87,8 @@ fn try_reparse(
// reject text that points to the special case for URL
// evasion and line comments.
if !child.kind().is_space()
&& child.kind() != &NodeKind::Semicolon
&& child.kind() != &NodeKind::Text('/'.into())
&& child.kind() != &SyntaxKind::Semicolon
&& child.kind() != &SyntaxKind::Text('/'.into())
&& (ahead.is_none() || change.replaced.start > child_span.end)
&& !ahead.map_or(false, Ahead::is_compulsory)
{
@ -153,8 +153,8 @@ fn try_reparse(
let superseded_span = pos.offset..pos.offset + prev_len;
let func: Option<ReparseMode> = match child.kind() {
NodeKind::CodeBlock => Some(ReparseMode::Code),
NodeKind::ContentBlock => Some(ReparseMode::Content),
SyntaxKind::CodeBlock => Some(ReparseMode::Code),
SyntaxKind::ContentBlock => Some(ReparseMode::Content),
_ => None,
};
@ -177,7 +177,7 @@ fn try_reparse(
// Make sure this is a markup node and that we may replace. If so, save
// the current indent.
let min_indent = match node.kind() {
NodeKind::Markup { min_indent } if safe_to_replace => *min_indent,
SyntaxKind::Markup { min_indent } if safe_to_replace => *min_indent,
_ => return None,
};
@ -375,26 +375,28 @@ enum ReparseMode {
/// Whether changes _inside_ this node are safely encapsulated, so that only
/// this node must be reparsed.
fn is_bounded(kind: &NodeKind) -> bool {
fn is_bounded(kind: &SyntaxKind) -> bool {
matches!(
kind,
NodeKind::CodeBlock
| NodeKind::ContentBlock
| NodeKind::Linebreak
| NodeKind::SmartQuote { .. }
| NodeKind::BlockComment
| NodeKind::Space { .. }
| NodeKind::Escape(_)
| NodeKind::Shorthand(_)
SyntaxKind::CodeBlock
| SyntaxKind::ContentBlock
| SyntaxKind::Linebreak
| SyntaxKind::SmartQuote { .. }
| SyntaxKind::BlockComment
| SyntaxKind::Space { .. }
| SyntaxKind::Escape(_)
| SyntaxKind::Shorthand(_)
)
}
/// Whether `at_start` would still be true after this node given the
/// previous value of the property.
fn next_at_start(kind: &NodeKind, prev: bool) -> bool {
fn next_at_start(kind: &SyntaxKind, prev: bool) -> bool {
match kind {
NodeKind::Space { newlines: (1..) } => true,
NodeKind::Space { .. } | NodeKind::LineComment | NodeKind::BlockComment => prev,
SyntaxKind::Space { newlines: (1..) } => true,
SyntaxKind::Space { .. } | SyntaxKind::LineComment | SyntaxKind::BlockComment => {
prev
}
_ => false,
}
}

View File

@ -6,10 +6,9 @@ use crate::util::EcoString;
/// All syntactical building blocks that can be part of a Typst document.
///
/// Can be emitted as a token by the tokenizer or as part of a syntax node by
/// the parser.
/// Can be created by the tokenizer or by the parser.
#[derive(Debug, Clone, PartialEq)]
pub enum NodeKind {
pub enum SyntaxKind {
/// A line comment: `// ...`.
LineComment,
/// A block comment: `/* ... */`.
@ -254,7 +253,7 @@ pub enum NodeKind {
Error(ErrorPos, EcoString),
}
/// Fields of a [`Raw`](NodeKind::Raw) node.
/// Fields of the raw syntax kind.
#[derive(Debug, Clone, PartialEq, Hash)]
pub struct RawFields {
/// An optional identifier specifying the language to syntax-highlight in.
@ -293,7 +292,7 @@ pub enum ErrorPos {
End,
}
impl NodeKind {
impl SyntaxKind {
/// Whether this is trivia.
pub fn is_trivia(&self) -> bool {
self.is_space() || matches!(self, Self::LineComment | Self::BlockComment)
@ -311,18 +310,18 @@ impl NodeKind {
/// Whether this is an error.
pub fn is_error(&self) -> bool {
matches!(self, NodeKind::Error(_, _))
matches!(self, SyntaxKind::Error(_, _))
}
/// Does this node need termination through a semicolon or linebreak?
pub fn is_stmt(&self) -> bool {
matches!(
self,
NodeKind::LetBinding
| NodeKind::SetRule
| NodeKind::ShowRule
| NodeKind::ModuleImport
| NodeKind::ModuleInclude
SyntaxKind::LetBinding
| SyntaxKind::SetRule
| SyntaxKind::ShowRule
| SyntaxKind::ModuleImport
| SyntaxKind::ModuleInclude
)
}
@ -445,7 +444,7 @@ impl NodeKind {
}
}
impl Hash for NodeKind {
impl Hash for SyntaxKind {
fn hash<H: Hasher>(&self, state: &mut H) {
std::mem::discriminant(self).hash(state);
match self {

View File

@ -1,9 +1,9 @@
use std::fmt::{self, Debug, Formatter};
use std::fmt::{self, Debug, Display, Formatter};
use std::ops::Range;
use std::sync::Arc;
use super::ast::TypedNode;
use super::{NodeKind, NumberingResult, SourceId, Span, Unnumberable};
use super::ast::AstNode;
use super::{SourceId, Span, SyntaxKind};
use crate::diag::SourceError;
/// A node in the untyped syntax tree.
@ -21,22 +21,22 @@ enum Repr {
impl SyntaxNode {
/// Create a new leaf node.
pub fn leaf(kind: NodeKind, len: usize) -> Self {
pub fn leaf(kind: SyntaxKind, len: usize) -> Self {
Self(Repr::Leaf(NodeData::new(kind, len)))
}
/// Create a new inner node with children.
pub fn inner(kind: NodeKind, children: Vec<SyntaxNode>) -> Self {
pub fn inner(kind: SyntaxKind, children: Vec<SyntaxNode>) -> Self {
Self(Repr::Inner(Arc::new(InnerNode::with_children(kind, children))))
}
/// The type of the node.
pub fn kind(&self) -> &NodeKind {
pub fn kind(&self) -> &SyntaxKind {
&self.data().kind
}
/// Take the kind out of the node.
pub fn take(self) -> NodeKind {
pub fn take(self) -> SyntaxKind {
match self.0 {
Repr::Leaf(leaf) => leaf.kind,
Repr::Inner(inner) => inner.data.kind.clone(),
@ -72,18 +72,18 @@ impl SyntaxNode {
/// Convert the node to a typed AST node.
pub fn cast<T>(&self) -> Option<T>
where
T: TypedNode,
T: AstNode,
{
T::from_untyped(self)
}
/// Get the first child that can cast to the AST type `T`.
pub fn cast_first_child<T: TypedNode>(&self) -> Option<T> {
pub fn cast_first_child<T: AstNode>(&self) -> Option<T> {
self.children().find_map(Self::cast)
}
/// Get the last child that can cast to the AST type `T`.
pub fn cast_last_child<T: TypedNode>(&self) -> Option<T> {
pub fn cast_last_child<T: AstNode>(&self) -> Option<T> {
self.children().rev().find_map(Self::cast)
}
@ -102,7 +102,7 @@ impl SyntaxNode {
}
match self.kind() {
NodeKind::Error(pos, message) => {
SyntaxKind::Error(pos, message) => {
vec![SourceError::new(self.span(), message.clone()).with_pos(*pos)]
}
_ => self
@ -114,7 +114,7 @@ impl SyntaxNode {
}
/// Change the type of the node.
pub(super) fn convert(&mut self, kind: NodeKind) {
pub(super) fn convert(&mut self, kind: SyntaxKind) {
match &mut self.0 {
Repr::Inner(inner) => {
let node = Arc::make_mut(inner);
@ -226,7 +226,7 @@ impl Debug for SyntaxNode {
impl Default for SyntaxNode {
fn default() -> Self {
Self::leaf(NodeKind::None, 0)
Self::leaf(SyntaxKind::None, 0)
}
}
@ -247,7 +247,7 @@ struct InnerNode {
impl InnerNode {
/// Create a new inner node with the given kind and children.
fn with_children(kind: NodeKind, children: Vec<SyntaxNode>) -> Self {
fn with_children(kind: SyntaxKind, children: Vec<SyntaxNode>) -> Self {
let mut len = 0;
let mut descendants = 1;
let mut erroneous = kind.is_error();
@ -305,7 +305,7 @@ impl InnerNode {
}
}
// Number this node itself.
// Number the node itself.
let mut start = within.start;
if range.is_none() {
let end = start + stride;
@ -480,7 +480,7 @@ impl PartialEq for InnerNode {
struct NodeData {
/// What kind of node this is (each kind would have its own struct in a
/// strongly typed AST).
kind: NodeKind,
kind: SyntaxKind,
/// The byte length of the node in the source.
len: usize,
/// The node's span.
@ -489,7 +489,7 @@ struct NodeData {
impl NodeData {
/// Create new node metadata.
fn new(kind: NodeKind, len: usize) -> Self {
fn new(kind: SyntaxKind, len: usize) -> Self {
Self { len, kind, span: Span::detached() }
}
@ -525,3 +525,18 @@ impl PartialEq for NodeData {
self.kind == other.kind && self.len == other.len
}
}
/// Result of numbering a node within an interval.
pub(super) type NumberingResult = Result<(), Unnumberable>;
/// Indicates that a node cannot be numbered within a given interval.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub(super) struct Unnumberable;
impl Display for Unnumberable {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.pad("cannot number within this interval")
}
}
impl std::error::Error for Unnumberable {}

View File

@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
use std::mem;
use std::ops::Range;
use super::{ErrorPos, NodeKind, SyntaxNode, TokenMode, Tokens};
use super::{ErrorPos, SyntaxKind, SyntaxNode, TokenMode, Tokens};
use crate::util::{format_eco, EcoString};
/// A convenient token-based parser.
@ -12,7 +12,7 @@ pub struct Parser<'s> {
/// Whether we are at the end of the file or of a group.
eof: bool,
/// The current token.
current: Option<NodeKind>,
current: Option<SyntaxKind>,
/// The end byte index of the last non-trivia token.
prev_end: usize,
/// The start byte index of the peeked token.
@ -82,7 +82,7 @@ impl<'s> Parser<'s> {
}
/// Perform a subparse that wraps its result in a node with the given kind.
pub fn perform<F, T>(&mut self, kind: NodeKind, f: F) -> T
pub fn perform<F, T>(&mut self, kind: SyntaxKind, f: F) -> T
where
F: FnOnce(&mut Self) -> T,
{
@ -112,9 +112,9 @@ impl<'s> Parser<'s> {
/// Consume the current token and also trailing trivia.
pub fn eat(&mut self) {
self.stray_terminator |= match self.current {
Some(NodeKind::RightParen) => !self.inside(Group::Paren),
Some(NodeKind::RightBracket) => !self.inside(Group::Bracket),
Some(NodeKind::RightBrace) => !self.inside(Group::Brace),
Some(SyntaxKind::RightParen) => !self.inside(Group::Paren),
Some(SyntaxKind::RightBracket) => !self.inside(Group::Bracket),
Some(SyntaxKind::RightBrace) => !self.inside(Group::Brace),
_ => false,
};
@ -132,7 +132,7 @@ impl<'s> Parser<'s> {
}
/// Consume the current token if it is the given one.
pub fn eat_if(&mut self, kind: NodeKind) -> bool {
pub fn eat_if(&mut self, kind: SyntaxKind) -> bool {
let at = self.at(kind);
if at {
self.eat();
@ -143,7 +143,7 @@ impl<'s> Parser<'s> {
/// Eat tokens while the condition is true.
pub fn eat_while<F>(&mut self, mut f: F)
where
F: FnMut(&NodeKind) -> bool,
F: FnMut(&SyntaxKind) -> bool,
{
while self.peek().map_or(false, |t| f(t)) {
self.eat();
@ -152,7 +152,7 @@ impl<'s> Parser<'s> {
/// Consume the current token if it is the given one and produce an error if
/// not.
pub fn expect(&mut self, kind: NodeKind) -> ParseResult {
pub fn expect(&mut self, kind: SyntaxKind) -> ParseResult {
let at = self.peek() == Some(&kind);
if at {
self.eat();
@ -165,18 +165,18 @@ impl<'s> Parser<'s> {
/// Consume the current token, debug-asserting that it is the given one.
#[track_caller]
pub fn assert(&mut self, kind: NodeKind) {
pub fn assert(&mut self, kind: SyntaxKind) {
debug_assert_eq!(self.peek(), Some(&kind));
self.eat();
}
/// Whether the current token is of the given type.
pub fn at(&self, kind: NodeKind) -> bool {
pub fn at(&self, kind: SyntaxKind) -> bool {
self.peek() == Some(&kind)
}
/// Peek at the current token without consuming it.
pub fn peek(&self) -> Option<&NodeKind> {
pub fn peek(&self) -> Option<&SyntaxKind> {
if self.eof {
None
} else {
@ -186,7 +186,7 @@ impl<'s> Parser<'s> {
/// Peek at the current token, but only if it follows immediately after the
/// last one without any trivia in between.
pub fn peek_direct(&self) -> Option<&NodeKind> {
pub fn peek_direct(&self) -> Option<&SyntaxKind> {
if self.prev_end() == self.current_start() {
self.peek()
} else {
@ -249,12 +249,12 @@ impl<'s> Parser<'s> {
});
match kind {
Group::Brace => self.assert(NodeKind::LeftBrace),
Group::Bracket => self.assert(NodeKind::LeftBracket),
Group::Paren => self.assert(NodeKind::LeftParen),
Group::Strong => self.assert(NodeKind::Star),
Group::Emph => self.assert(NodeKind::Underscore),
Group::Math => self.assert(NodeKind::Dollar),
Group::Brace => self.assert(SyntaxKind::LeftBrace),
Group::Bracket => self.assert(SyntaxKind::LeftBracket),
Group::Paren => self.assert(SyntaxKind::LeftParen),
Group::Strong => self.assert(SyntaxKind::Star),
Group::Emph => self.assert(SyntaxKind::Underscore),
Group::Math => self.assert(SyntaxKind::Dollar),
Group::Expr => self.repeek(),
Group::Imports => self.repeek(),
}
@ -273,13 +273,13 @@ impl<'s> Parser<'s> {
// Eat the end delimiter if there is one.
if let Some((end, required)) = match group.kind {
Group::Brace => Some((NodeKind::RightBrace, true)),
Group::Bracket => Some((NodeKind::RightBracket, true)),
Group::Paren => Some((NodeKind::RightParen, true)),
Group::Strong => Some((NodeKind::Star, true)),
Group::Emph => Some((NodeKind::Underscore, true)),
Group::Math => Some((NodeKind::Dollar, true)),
Group::Expr => Some((NodeKind::Semicolon, false)),
Group::Brace => Some((SyntaxKind::RightBrace, true)),
Group::Bracket => Some((SyntaxKind::RightBracket, true)),
Group::Paren => Some((SyntaxKind::RightParen, true)),
Group::Strong => Some((SyntaxKind::Star, true)),
Group::Emph => Some((SyntaxKind::Underscore, true)),
Group::Math => Some((SyntaxKind::Dollar, true)),
Group::Expr => Some((SyntaxKind::Semicolon, false)),
Group::Imports => None,
} {
if self.current.as_ref() == Some(&end) {
@ -339,26 +339,26 @@ impl<'s> Parser<'s> {
/// group.
fn repeek(&mut self) {
self.eof = match &self.current {
Some(NodeKind::RightBrace) => self.inside(Group::Brace),
Some(NodeKind::RightBracket) => self.inside(Group::Bracket),
Some(NodeKind::RightParen) => self.inside(Group::Paren),
Some(NodeKind::Star) => self.inside(Group::Strong),
Some(NodeKind::Underscore) => self.inside(Group::Emph),
Some(NodeKind::Dollar) => self.inside(Group::Math),
Some(NodeKind::Semicolon) => self.inside(Group::Expr),
Some(NodeKind::From) => self.inside(Group::Imports),
Some(NodeKind::Space { newlines }) => self.space_ends_group(*newlines),
Some(SyntaxKind::RightBrace) => self.inside(Group::Brace),
Some(SyntaxKind::RightBracket) => self.inside(Group::Bracket),
Some(SyntaxKind::RightParen) => self.inside(Group::Paren),
Some(SyntaxKind::Star) => self.inside(Group::Strong),
Some(SyntaxKind::Underscore) => self.inside(Group::Emph),
Some(SyntaxKind::Dollar) => self.inside(Group::Math),
Some(SyntaxKind::Semicolon) => self.inside(Group::Expr),
Some(SyntaxKind::From) => self.inside(Group::Imports),
Some(SyntaxKind::Space { newlines }) => self.space_ends_group(*newlines),
Some(_) => false,
None => true,
};
}
/// Returns whether the given type can be skipped over.
fn is_trivia(&self, token: &NodeKind) -> bool {
fn is_trivia(&self, token: &SyntaxKind) -> bool {
match token {
NodeKind::Space { newlines } => !self.space_ends_group(*newlines),
NodeKind::LineComment => true,
NodeKind::BlockComment => true,
SyntaxKind::Space { newlines } => !self.space_ends_group(*newlines),
SyntaxKind::LineComment => true,
SyntaxKind::BlockComment => true,
_ => false,
}
}
@ -378,7 +378,7 @@ impl<'s> Parser<'s> {
!= Some(Group::Brace)
|| !matches!(
self.tokens.clone().next(),
Some(NodeKind::Else | NodeKind::Dot)
Some(SyntaxKind::Else | SyntaxKind::Dot)
)
}
_ => false,
@ -401,7 +401,7 @@ impl Parser<'_> {
pub fn unexpected(&mut self) {
if let Some(found) = self.peek() {
let msg = format_eco!("unexpected {}", found.name());
let error = NodeKind::Error(ErrorPos::Full, msg);
let error = SyntaxKind::Error(ErrorPos::Full, msg);
self.perform(error, Self::eat);
}
}
@ -415,7 +415,7 @@ impl Parser<'_> {
/// Insert an error message that `what` was expected at the marker position.
pub fn expected_at(&mut self, marker: Marker, what: &str) {
let msg = format_eco!("expected {}", what);
let error = NodeKind::Error(ErrorPos::Full, msg);
let error = SyntaxKind::Error(ErrorPos::Full, msg);
self.children.insert(marker.0, SyntaxNode::leaf(error, 0));
}
@ -425,7 +425,7 @@ impl Parser<'_> {
match self.peek() {
Some(found) => {
let msg = format_eco!("expected {}, found {}", thing, found.name());
let error = NodeKind::Error(ErrorPos::Full, msg);
let error = SyntaxKind::Error(ErrorPos::Full, msg);
self.perform(error, Self::eat);
}
None => self.expected(thing),
@ -449,7 +449,7 @@ impl Marker {
}
/// Convert the child directly after marker.
pub fn convert(self, p: &mut Parser, kind: NodeKind) {
pub fn convert(self, p: &mut Parser, kind: SyntaxKind) {
if let Some(child) = p.children.get_mut(self.0) {
child.convert(kind);
}
@ -457,7 +457,7 @@ impl Marker {
/// Perform a subparse that wraps all children after the marker in a node
/// with the given kind.
pub fn perform<T, F>(self, p: &mut Parser, kind: NodeKind, f: F) -> T
pub fn perform<T, F>(self, p: &mut Parser, kind: SyntaxKind, f: F) -> T
where
F: FnOnce(&mut Parser) -> T,
{
@ -468,7 +468,7 @@ impl Marker {
/// Wrap all children after the marker (excluding trailing trivia) in a node
/// with the given `kind`.
pub fn end(self, p: &mut Parser, kind: NodeKind) {
pub fn end(self, p: &mut Parser, kind: SyntaxKind) {
let until = p.trivia_start().0.max(self.0);
let children = p.children.drain(self.0..until).collect();
p.children.insert(self.0, SyntaxNode::inner(kind, children));
@ -496,7 +496,7 @@ impl Marker {
msg.push_str(", found ");
msg.push_str(child.kind().name());
}
let error = NodeKind::Error(ErrorPos::Full, msg);
let error = SyntaxKind::Error(ErrorPos::Full, msg);
let inner = mem::take(child);
*child = SyntaxNode::inner(error, vec![inner]);
}

View File

@ -2,7 +2,7 @@ use std::collections::HashSet;
use super::ast::{Assoc, BinOp, UnOp};
use super::{
ErrorPos, Group, Marker, NodeKind, ParseError, ParseResult, Parser, SyntaxNode,
ErrorPos, Group, Marker, ParseError, ParseResult, Parser, SyntaxKind, SyntaxNode,
TokenMode,
};
use crate::util::EcoString;
@ -17,7 +17,7 @@ pub fn parse(text: &str) -> SyntaxNode {
/// Parse code directly, only used for syntax highlighting.
pub fn parse_code(text: &str) -> SyntaxNode {
let mut p = Parser::new(text, TokenMode::Code);
p.perform(NodeKind::CodeBlock, code);
p.perform(SyntaxKind::CodeBlock, code);
p.finish().into_iter().next().unwrap()
}
@ -30,7 +30,7 @@ pub(crate) fn reparse_code_block(
end_pos: usize,
) -> Option<(Vec<SyntaxNode>, bool, usize)> {
let mut p = Parser::with_prefix(prefix, text, TokenMode::Code);
if !p.at(NodeKind::LeftBrace) {
if !p.at(SyntaxKind::LeftBrace) {
return None;
}
@ -54,7 +54,7 @@ pub(crate) fn reparse_content_block(
end_pos: usize,
) -> Option<(Vec<SyntaxNode>, bool, usize)> {
let mut p = Parser::with_prefix(prefix, text, TokenMode::Code);
if !p.at(NodeKind::LeftBracket) {
if !p.at(SyntaxKind::LeftBracket) {
return None;
}
@ -90,7 +90,7 @@ pub(crate) fn reparse_markup_elements(
let mut stopped = false;
'outer: while !p.eof() {
if let Some(NodeKind::Space { newlines: (1..) }) = p.peek() {
if let Some(SyntaxKind::Space { newlines: (1..) }) = p.peek() {
if p.column(p.current_end()) < min_indent {
return None;
}
@ -147,7 +147,7 @@ pub(crate) fn reparse_markup_elements(
/// If `at_start` is true, things like headings that may only appear at the
/// beginning of a line or content block are initially allowed.
fn markup(p: &mut Parser, mut at_start: bool) {
p.perform(NodeKind::Markup { min_indent: 0 }, |p| {
p.perform(SyntaxKind::Markup { min_indent: 0 }, |p| {
while !p.eof() {
markup_node(p, &mut at_start);
}
@ -157,8 +157,8 @@ fn markup(p: &mut Parser, mut at_start: bool) {
/// Parse markup that stays right of the given `column`.
fn markup_indented(p: &mut Parser, min_indent: usize) {
p.eat_while(|t| match t {
NodeKind::Space { newlines } => *newlines == 0,
NodeKind::LineComment | NodeKind::BlockComment => true,
SyntaxKind::Space { newlines } => *newlines == 0,
SyntaxKind::LineComment | SyntaxKind::BlockComment => true,
_ => false,
});
@ -167,7 +167,7 @@ fn markup_indented(p: &mut Parser, min_indent: usize) {
while !p.eof() {
match p.peek() {
Some(NodeKind::Space { newlines: (1..) })
Some(SyntaxKind::Space { newlines: (1..) })
if p.column(p.current_end()) < min_indent =>
{
break;
@ -178,24 +178,24 @@ fn markup_indented(p: &mut Parser, min_indent: usize) {
markup_node(p, &mut at_start);
}
marker.end(p, NodeKind::Markup { min_indent });
marker.end(p, SyntaxKind::Markup { min_indent });
}
/// Parse a line of markup that can prematurely end if `f` returns true.
fn markup_line<F>(p: &mut Parser, mut f: F)
where
F: FnMut(&NodeKind) -> bool,
F: FnMut(&SyntaxKind) -> bool,
{
p.eat_while(|t| match t {
NodeKind::Space { newlines } => *newlines == 0,
NodeKind::LineComment | NodeKind::BlockComment => true,
SyntaxKind::Space { newlines } => *newlines == 0,
SyntaxKind::LineComment | SyntaxKind::BlockComment => true,
_ => false,
});
p.perform(NodeKind::Markup { min_indent: usize::MAX }, |p| {
p.perform(SyntaxKind::Markup { min_indent: usize::MAX }, |p| {
let mut at_start = false;
while let Some(kind) = p.peek() {
if let NodeKind::Space { newlines: (1..) } = kind {
if let SyntaxKind::Space { newlines: (1..) } = kind {
break;
}
@ -212,68 +212,68 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) {
let Some(token) = p.peek() else { return };
match token {
// Whitespace.
NodeKind::Space { newlines } => {
SyntaxKind::Space { newlines } => {
*at_start |= *newlines > 0;
p.eat();
return;
}
// Comments.
NodeKind::LineComment | NodeKind::BlockComment => {
SyntaxKind::LineComment | SyntaxKind::BlockComment => {
p.eat();
return;
}
// Text and markup.
NodeKind::Text(_)
| NodeKind::Linebreak
| NodeKind::SmartQuote { .. }
| NodeKind::Escape(_)
| NodeKind::Shorthand(_)
| NodeKind::Link(_)
| NodeKind::Raw(_)
| NodeKind::Label(_)
| NodeKind::Ref(_) => p.eat(),
SyntaxKind::Text(_)
| SyntaxKind::Linebreak
| SyntaxKind::SmartQuote { .. }
| SyntaxKind::Escape(_)
| SyntaxKind::Shorthand(_)
| SyntaxKind::Link(_)
| SyntaxKind::Raw(_)
| SyntaxKind::Label(_)
| SyntaxKind::Ref(_) => p.eat(),
// Math.
NodeKind::Dollar => math(p),
SyntaxKind::Dollar => math(p),
// Strong, emph, heading.
NodeKind::Star => strong(p),
NodeKind::Underscore => emph(p),
NodeKind::Eq => heading(p, *at_start),
SyntaxKind::Star => strong(p),
SyntaxKind::Underscore => emph(p),
SyntaxKind::Eq => heading(p, *at_start),
// Lists.
NodeKind::Minus => list_item(p, *at_start),
NodeKind::Plus | NodeKind::EnumNumbering(_) => enum_item(p, *at_start),
NodeKind::Slash => {
SyntaxKind::Minus => list_item(p, *at_start),
SyntaxKind::Plus | SyntaxKind::EnumNumbering(_) => enum_item(p, *at_start),
SyntaxKind::Slash => {
desc_item(p, *at_start).ok();
}
NodeKind::Colon => {
SyntaxKind::Colon => {
let marker = p.marker();
p.eat();
marker.convert(p, NodeKind::Text(':'.into()));
marker.convert(p, SyntaxKind::Text(':'.into()));
}
// Hashtag + keyword / identifier.
NodeKind::Ident(_)
| NodeKind::Let
| NodeKind::Set
| NodeKind::Show
| NodeKind::If
| NodeKind::While
| NodeKind::For
| NodeKind::Import
| NodeKind::Include
| NodeKind::Break
| NodeKind::Continue
| NodeKind::Return => markup_expr(p),
SyntaxKind::Ident(_)
| SyntaxKind::Let
| SyntaxKind::Set
| SyntaxKind::Show
| SyntaxKind::If
| SyntaxKind::While
| SyntaxKind::For
| SyntaxKind::Import
| SyntaxKind::Include
| SyntaxKind::Break
| SyntaxKind::Continue
| SyntaxKind::Return => markup_expr(p),
// Code and content block.
NodeKind::LeftBrace => code_block(p),
NodeKind::LeftBracket => content_block(p),
SyntaxKind::LeftBrace => code_block(p),
SyntaxKind::LeftBracket => content_block(p),
NodeKind::Error(_, _) => p.eat(),
SyntaxKind::Error(_, _) => p.eat(),
_ => p.unexpected(),
};
@ -281,7 +281,7 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) {
}
fn strong(p: &mut Parser) {
p.perform(NodeKind::Strong, |p| {
p.perform(SyntaxKind::Strong, |p| {
p.start_group(Group::Strong);
markup(p, false);
p.end_group();
@ -289,7 +289,7 @@ fn strong(p: &mut Parser) {
}
fn emph(p: &mut Parser) {
p.perform(NodeKind::Emph, |p| {
p.perform(SyntaxKind::Emph, |p| {
p.start_group(Group::Emph);
markup(p, false);
p.end_group();
@ -299,30 +299,30 @@ fn emph(p: &mut Parser) {
fn heading(p: &mut Parser, at_start: bool) {
let marker = p.marker();
let current_start = p.current_start();
p.assert(NodeKind::Eq);
while p.eat_if(NodeKind::Eq) {}
p.assert(SyntaxKind::Eq);
while p.eat_if(SyntaxKind::Eq) {}
if at_start && p.peek().map_or(true, |kind| kind.is_space()) {
p.eat_while(|kind| *kind == NodeKind::Space { newlines: 0 });
markup_line(p, |kind| matches!(kind, NodeKind::Label(_)));
marker.end(p, NodeKind::Heading);
p.eat_while(|kind| *kind == SyntaxKind::Space { newlines: 0 });
markup_line(p, |kind| matches!(kind, SyntaxKind::Label(_)));
marker.end(p, SyntaxKind::Heading);
} else {
let text = p.get(current_start..p.prev_end()).into();
marker.convert(p, NodeKind::Text(text));
marker.convert(p, SyntaxKind::Text(text));
}
}
fn list_item(p: &mut Parser, at_start: bool) {
let marker = p.marker();
let text: EcoString = p.peek_src().into();
p.assert(NodeKind::Minus);
p.assert(SyntaxKind::Minus);
let min_indent = p.column(p.prev_end());
if at_start && p.eat_if(NodeKind::Space { newlines: 0 }) && !p.eof() {
if at_start && p.eat_if(SyntaxKind::Space { newlines: 0 }) && !p.eof() {
markup_indented(p, min_indent);
marker.end(p, NodeKind::ListItem);
marker.end(p, SyntaxKind::ListItem);
} else {
marker.convert(p, NodeKind::Text(text));
marker.convert(p, SyntaxKind::Text(text));
}
}
@ -332,11 +332,11 @@ fn enum_item(p: &mut Parser, at_start: bool) {
p.eat();
let min_indent = p.column(p.prev_end());
if at_start && p.eat_if(NodeKind::Space { newlines: 0 }) && !p.eof() {
if at_start && p.eat_if(SyntaxKind::Space { newlines: 0 }) && !p.eof() {
markup_indented(p, min_indent);
marker.end(p, NodeKind::EnumItem);
marker.end(p, SyntaxKind::EnumItem);
} else {
marker.convert(p, NodeKind::Text(text));
marker.convert(p, SyntaxKind::Text(text));
}
}
@ -346,13 +346,13 @@ fn desc_item(p: &mut Parser, at_start: bool) -> ParseResult {
p.eat();
let min_indent = p.column(p.prev_end());
if at_start && p.eat_if(NodeKind::Space { newlines: 0 }) && !p.eof() {
markup_line(p, |node| matches!(node, NodeKind::Colon));
p.expect(NodeKind::Colon)?;
if at_start && p.eat_if(SyntaxKind::Space { newlines: 0 }) && !p.eof() {
markup_line(p, |node| matches!(node, SyntaxKind::Colon));
p.expect(SyntaxKind::Colon)?;
markup_indented(p, min_indent);
marker.end(p, NodeKind::DescItem);
marker.end(p, SyntaxKind::DescItem);
} else {
marker.convert(p, NodeKind::Text(text));
marker.convert(p, SyntaxKind::Text(text));
}
Ok(())
@ -363,11 +363,11 @@ fn markup_expr(p: &mut Parser) {
let stmt = matches!(
p.peek(),
Some(
NodeKind::Let
| NodeKind::Set
| NodeKind::Show
| NodeKind::Import
| NodeKind::Include
SyntaxKind::Let
| SyntaxKind::Set
| SyntaxKind::Show
| SyntaxKind::Import
| SyntaxKind::Include
)
);
@ -380,7 +380,7 @@ fn markup_expr(p: &mut Parser) {
}
fn math(p: &mut Parser) {
p.perform(NodeKind::Math, |p| {
p.perform(SyntaxKind::Math, |p| {
p.start_group(Group::Math);
while !p.eof() {
math_node(p);
@ -393,20 +393,20 @@ fn math_node(p: &mut Parser) {
math_node_prec(p, 0, None)
}
fn math_node_prec(p: &mut Parser, min_prec: usize, stop: Option<NodeKind>) {
fn math_node_prec(p: &mut Parser, min_prec: usize, stop: Option<SyntaxKind>) {
let marker = p.marker();
math_primary(p);
loop {
let (kind, mut prec, assoc, stop) = match p.peek() {
v if v == stop.as_ref() => break,
Some(NodeKind::Underscore) => {
(NodeKind::Script, 2, Assoc::Right, Some(NodeKind::Hat))
Some(SyntaxKind::Underscore) => {
(SyntaxKind::Script, 2, Assoc::Right, Some(SyntaxKind::Hat))
}
Some(NodeKind::Hat) => {
(NodeKind::Script, 2, Assoc::Right, Some(NodeKind::Underscore))
Some(SyntaxKind::Hat) => {
(SyntaxKind::Script, 2, Assoc::Right, Some(SyntaxKind::Underscore))
}
Some(NodeKind::Slash) => (NodeKind::Frac, 1, Assoc::Left, None),
Some(SyntaxKind::Slash) => (SyntaxKind::Frac, 1, Assoc::Left, None),
_ => break,
};
@ -424,7 +424,7 @@ fn math_node_prec(p: &mut Parser, min_prec: usize, stop: Option<NodeKind>) {
// Allow up to two different scripts. We do not risk encountering the
// previous script kind again here due to right-associativity.
if p.eat_if(NodeKind::Underscore) || p.eat_if(NodeKind::Hat) {
if p.eat_if(SyntaxKind::Underscore) || p.eat_if(SyntaxKind::Hat) {
math_node_prec(p, prec, None);
}
@ -437,42 +437,42 @@ fn math_primary(p: &mut Parser) {
let Some(token) = p.peek() else { return };
match token {
// Spaces, atoms and expressions.
NodeKind::Space { .. }
| NodeKind::Linebreak
| NodeKind::Escape(_)
| NodeKind::Atom(_)
| NodeKind::Ident(_) => p.eat(),
SyntaxKind::Space { .. }
| SyntaxKind::Linebreak
| SyntaxKind::Escape(_)
| SyntaxKind::Atom(_)
| SyntaxKind::Ident(_) => p.eat(),
// Groups.
NodeKind::LeftParen => math_group(p, Group::Paren, '(', ')'),
NodeKind::LeftBracket => math_group(p, Group::Bracket, '[', ']'),
NodeKind::LeftBrace => math_group(p, Group::Brace, '{', '}'),
SyntaxKind::LeftParen => math_group(p, Group::Paren, '(', ')'),
SyntaxKind::LeftBracket => math_group(p, Group::Bracket, '[', ']'),
SyntaxKind::LeftBrace => math_group(p, Group::Brace, '{', '}'),
// Alignment indactor.
NodeKind::Amp => math_align(p),
SyntaxKind::Amp => math_align(p),
_ => p.unexpected(),
}
}
fn math_group(p: &mut Parser, group: Group, l: char, r: char) {
p.perform(NodeKind::Math, |p| {
p.perform(SyntaxKind::Math, |p| {
let marker = p.marker();
p.start_group(group);
marker.convert(p, NodeKind::Atom(l.into()));
marker.convert(p, SyntaxKind::Atom(l.into()));
while !p.eof() {
math_node(p);
}
let marker = p.marker();
p.end_group();
marker.convert(p, NodeKind::Atom(r.into()));
marker.convert(p, SyntaxKind::Atom(r.into()));
})
}
fn math_align(p: &mut Parser) {
p.perform(NodeKind::Align, |p| {
p.assert(NodeKind::Amp);
while p.eat_if(NodeKind::Amp) {}
p.perform(SyntaxKind::Align, |p| {
p.assert(SyntaxKind::Amp);
while p.eat_if(SyntaxKind::Amp) {}
})
}
@ -496,15 +496,15 @@ fn expr_prec(p: &mut Parser, atomic: bool, min_prec: usize) -> ParseResult {
p.eat();
let prec = op.precedence();
expr_prec(p, atomic, prec)?;
marker.end(p, NodeKind::Unary);
marker.end(p, SyntaxKind::Unary);
}
_ => primary(p, atomic)?,
};
loop {
// Parenthesis or bracket means this is a function call.
if let Some(NodeKind::LeftParen | NodeKind::LeftBracket) = p.peek_direct() {
marker.perform(p, NodeKind::FuncCall, args)?;
if let Some(SyntaxKind::LeftParen | SyntaxKind::LeftBracket) = p.peek_direct() {
marker.perform(p, SyntaxKind::FuncCall, args)?;
continue;
}
@ -513,18 +513,19 @@ fn expr_prec(p: &mut Parser, atomic: bool, min_prec: usize) -> ParseResult {
}
// Method call or field access.
if p.eat_if(NodeKind::Dot) {
if p.eat_if(SyntaxKind::Dot) {
ident(p)?;
if let Some(NodeKind::LeftParen | NodeKind::LeftBracket) = p.peek_direct() {
marker.perform(p, NodeKind::MethodCall, args)?;
if let Some(SyntaxKind::LeftParen | SyntaxKind::LeftBracket) = p.peek_direct()
{
marker.perform(p, SyntaxKind::MethodCall, args)?;
} else {
marker.end(p, NodeKind::FieldAccess);
marker.end(p, SyntaxKind::FieldAccess);
}
continue;
}
let op = if p.eat_if(NodeKind::Not) {
if p.at(NodeKind::In) {
let op = if p.eat_if(SyntaxKind::Not) {
if p.at(SyntaxKind::In) {
BinOp::NotIn
} else {
p.expected("keyword `in`");
@ -549,7 +550,7 @@ fn expr_prec(p: &mut Parser, atomic: bool, min_prec: usize) -> ParseResult {
Assoc::Right => {}
}
marker.perform(p, NodeKind::Binary, |p| expr_prec(p, atomic, prec))?;
marker.perform(p, SyntaxKind::Binary, |p| expr_prec(p, atomic, prec))?;
}
Ok(())
@ -562,39 +563,39 @@ fn primary(p: &mut Parser, atomic: bool) -> ParseResult {
match p.peek() {
// Things that start with an identifier.
Some(NodeKind::Ident(_)) => {
Some(SyntaxKind::Ident(_)) => {
let marker = p.marker();
p.eat();
// Arrow means this is a closure's lone parameter.
if !atomic && p.at(NodeKind::Arrow) {
marker.end(p, NodeKind::Params);
p.assert(NodeKind::Arrow);
marker.perform(p, NodeKind::Closure, expr)
if !atomic && p.at(SyntaxKind::Arrow) {
marker.end(p, SyntaxKind::Params);
p.assert(SyntaxKind::Arrow);
marker.perform(p, SyntaxKind::Closure, expr)
} else {
Ok(())
}
}
// Structures.
Some(NodeKind::LeftParen) => parenthesized(p, atomic),
Some(NodeKind::LeftBrace) => Ok(code_block(p)),
Some(NodeKind::LeftBracket) => Ok(content_block(p)),
Some(SyntaxKind::LeftParen) => parenthesized(p, atomic),
Some(SyntaxKind::LeftBrace) => Ok(code_block(p)),
Some(SyntaxKind::LeftBracket) => Ok(content_block(p)),
// Keywords.
Some(NodeKind::Let) => let_binding(p),
Some(NodeKind::Set) => set_rule(p),
Some(NodeKind::Show) => show_rule(p),
Some(NodeKind::If) => conditional(p),
Some(NodeKind::While) => while_loop(p),
Some(NodeKind::For) => for_loop(p),
Some(NodeKind::Import) => module_import(p),
Some(NodeKind::Include) => module_include(p),
Some(NodeKind::Break) => break_stmt(p),
Some(NodeKind::Continue) => continue_stmt(p),
Some(NodeKind::Return) => return_stmt(p),
Some(SyntaxKind::Let) => let_binding(p),
Some(SyntaxKind::Set) => set_rule(p),
Some(SyntaxKind::Show) => show_rule(p),
Some(SyntaxKind::If) => conditional(p),
Some(SyntaxKind::While) => while_loop(p),
Some(SyntaxKind::For) => for_loop(p),
Some(SyntaxKind::Import) => module_import(p),
Some(SyntaxKind::Include) => module_include(p),
Some(SyntaxKind::Break) => break_stmt(p),
Some(SyntaxKind::Continue) => continue_stmt(p),
Some(SyntaxKind::Return) => return_stmt(p),
Some(NodeKind::Error(_, _)) => {
Some(SyntaxKind::Error(_, _)) => {
p.eat();
Err(ParseError)
}
@ -610,13 +611,13 @@ fn primary(p: &mut Parser, atomic: bool) -> ParseResult {
fn literal(p: &mut Parser) -> bool {
match p.peek() {
Some(
NodeKind::None
| NodeKind::Auto
| NodeKind::Int(_)
| NodeKind::Float(_)
| NodeKind::Bool(_)
| NodeKind::Numeric(_, _)
| NodeKind::Str(_),
SyntaxKind::None
| SyntaxKind::Auto
| SyntaxKind::Int(_)
| SyntaxKind::Float(_)
| SyntaxKind::Bool(_)
| SyntaxKind::Numeric(_, _)
| SyntaxKind::Str(_),
) => {
p.eat();
true
@ -627,7 +628,7 @@ fn literal(p: &mut Parser) -> bool {
fn ident(p: &mut Parser) -> ParseResult {
match p.peek() {
Some(NodeKind::Ident(_)) => {
Some(SyntaxKind::Ident(_)) => {
p.eat();
Ok(())
}
@ -647,7 +648,7 @@ fn parenthesized(p: &mut Parser, atomic: bool) -> ParseResult {
let marker = p.marker();
p.start_group(Group::Paren);
let colon = p.eat_if(NodeKind::Colon);
let colon = p.eat_if(SyntaxKind::Colon);
let kind = collection(p, true).0;
p.end_group();
@ -658,15 +659,15 @@ fn parenthesized(p: &mut Parser, atomic: bool) -> ParseResult {
}
// Arrow means this is a closure's parameter list.
if !atomic && p.at(NodeKind::Arrow) {
if !atomic && p.at(SyntaxKind::Arrow) {
params(p, marker);
p.assert(NodeKind::Arrow);
return marker.perform(p, NodeKind::Closure, expr);
p.assert(SyntaxKind::Arrow);
return marker.perform(p, SyntaxKind::Closure, expr);
}
// Transform into the identified collection.
match kind {
CollectionKind::Group => marker.end(p, NodeKind::Parenthesized),
CollectionKind::Group => marker.end(p, SyntaxKind::Parenthesized),
CollectionKind::Positional => array(p, marker),
CollectionKind::Named => dict(p, marker),
}
@ -698,14 +699,14 @@ fn collection(p: &mut Parser, keyed: bool) -> (CollectionKind, usize) {
while !p.eof() {
let Ok(item_kind) = item(p, keyed) else {
p.eat_if(NodeKind::Comma);
p.eat_if(SyntaxKind::Comma);
collection_kind = Some(CollectionKind::Group);
continue;
};
match item_kind {
NodeKind::Spread => can_group = false,
NodeKind::Named if collection_kind.is_none() => {
SyntaxKind::Spread => can_group = false,
SyntaxKind::Named if collection_kind.is_none() => {
collection_kind = Some(CollectionKind::Named);
can_group = false;
}
@ -725,7 +726,7 @@ fn collection(p: &mut Parser, keyed: bool) -> (CollectionKind, usize) {
break;
}
if p.eat_if(NodeKind::Comma) {
if p.eat_if(SyntaxKind::Comma) {
can_group = false;
} else {
missing_coma = Some(p.trivia_start());
@ -741,24 +742,24 @@ fn collection(p: &mut Parser, keyed: bool) -> (CollectionKind, usize) {
(kind, items)
}
fn item(p: &mut Parser, keyed: bool) -> ParseResult<NodeKind> {
fn item(p: &mut Parser, keyed: bool) -> ParseResult<SyntaxKind> {
let marker = p.marker();
if p.eat_if(NodeKind::Dots) {
marker.perform(p, NodeKind::Spread, expr)?;
return Ok(NodeKind::Spread);
if p.eat_if(SyntaxKind::Dots) {
marker.perform(p, SyntaxKind::Spread, expr)?;
return Ok(SyntaxKind::Spread);
}
expr(p)?;
if p.at(NodeKind::Colon) {
if p.at(SyntaxKind::Colon) {
match marker.after(p).map(|c| c.kind()) {
Some(NodeKind::Ident(_)) => {
Some(SyntaxKind::Ident(_)) => {
p.eat();
marker.perform(p, NodeKind::Named, expr)?;
marker.perform(p, SyntaxKind::Named, expr)?;
}
Some(NodeKind::Str(_)) if keyed => {
Some(SyntaxKind::Str(_)) if keyed => {
p.eat();
marker.perform(p, NodeKind::Keyed, expr)?;
marker.perform(p, SyntaxKind::Keyed, expr)?;
}
kind => {
let mut msg = EcoString::from("expected identifier");
@ -769,34 +770,34 @@ fn item(p: &mut Parser, keyed: bool) -> ParseResult<NodeKind> {
msg.push_str(", found ");
msg.push_str(kind.name());
}
let error = NodeKind::Error(ErrorPos::Full, msg);
let error = SyntaxKind::Error(ErrorPos::Full, msg);
marker.end(p, error);
p.eat();
marker.perform(p, NodeKind::Named, expr).ok();
marker.perform(p, SyntaxKind::Named, expr).ok();
return Err(ParseError);
}
}
Ok(NodeKind::Named)
Ok(SyntaxKind::Named)
} else {
Ok(NodeKind::None)
Ok(SyntaxKind::None)
}
}
fn array(p: &mut Parser, marker: Marker) {
marker.filter_children(p, |x| match x.kind() {
NodeKind::Named | NodeKind::Keyed => Err("expected expression"),
SyntaxKind::Named | SyntaxKind::Keyed => Err("expected expression"),
_ => Ok(()),
});
marker.end(p, NodeKind::Array);
marker.end(p, SyntaxKind::Array);
}
fn dict(p: &mut Parser, marker: Marker) {
let mut used = HashSet::new();
marker.filter_children(p, |x| match x.kind() {
kind if kind.is_paren() => Ok(()),
NodeKind::Named | NodeKind::Keyed => {
if let Some(NodeKind::Ident(key) | NodeKind::Str(key)) =
SyntaxKind::Named | SyntaxKind::Keyed => {
if let Some(SyntaxKind::Ident(key) | SyntaxKind::Str(key)) =
x.children().next().map(|child| child.kind())
{
if !used.insert(key.clone()) {
@ -805,32 +806,32 @@ fn dict(p: &mut Parser, marker: Marker) {
}
Ok(())
}
NodeKind::Spread | NodeKind::Comma | NodeKind::Colon => Ok(()),
SyntaxKind::Spread | SyntaxKind::Comma | SyntaxKind::Colon => Ok(()),
_ => Err("expected named or keyed pair"),
});
marker.end(p, NodeKind::Dict);
marker.end(p, SyntaxKind::Dict);
}
fn params(p: &mut Parser, marker: Marker) {
marker.filter_children(p, |x| match x.kind() {
kind if kind.is_paren() => Ok(()),
NodeKind::Named | NodeKind::Ident(_) | NodeKind::Comma => Ok(()),
NodeKind::Spread
SyntaxKind::Named | SyntaxKind::Ident(_) | SyntaxKind::Comma => Ok(()),
SyntaxKind::Spread
if matches!(
x.children().last().map(|child| child.kind()),
Some(&NodeKind::Ident(_))
Some(&SyntaxKind::Ident(_))
) =>
{
Ok(())
}
_ => Err("expected identifier, named pair or argument sink"),
});
marker.end(p, NodeKind::Params);
marker.end(p, SyntaxKind::Params);
}
/// Parse a code block: `{...}`.
fn code_block(p: &mut Parser) {
p.perform(NodeKind::CodeBlock, |p| {
p.perform(SyntaxKind::CodeBlock, |p| {
p.start_group(Group::Brace);
code(p);
p.end_group();
@ -846,12 +847,12 @@ fn code(p: &mut Parser) {
p.end_group();
// Forcefully skip over newlines since the group's contents can't.
p.eat_while(NodeKind::is_space);
p.eat_while(SyntaxKind::is_space);
}
}
fn content_block(p: &mut Parser) {
p.perform(NodeKind::ContentBlock, |p| {
p.perform(SyntaxKind::ContentBlock, |p| {
p.start_group(Group::Bracket);
markup(p, true);
p.end_group();
@ -860,16 +861,16 @@ fn content_block(p: &mut Parser) {
fn args(p: &mut Parser) -> ParseResult {
match p.peek_direct() {
Some(NodeKind::LeftParen) => {}
Some(NodeKind::LeftBracket) => {}
Some(SyntaxKind::LeftParen) => {}
Some(SyntaxKind::LeftBracket) => {}
_ => {
p.expected_found("argument list");
return Err(ParseError);
}
}
p.perform(NodeKind::Args, |p| {
if p.at(NodeKind::LeftParen) {
p.perform(SyntaxKind::Args, |p| {
if p.at(SyntaxKind::LeftParen) {
let marker = p.marker();
p.start_group(Group::Paren);
collection(p, false);
@ -877,8 +878,8 @@ fn args(p: &mut Parser) -> ParseResult {
let mut used = HashSet::new();
marker.filter_children(p, |x| match x.kind() {
NodeKind::Named => {
if let Some(NodeKind::Ident(ident)) =
SyntaxKind::Named => {
if let Some(SyntaxKind::Ident(ident)) =
x.children().next().map(|child| child.kind())
{
if !used.insert(ident.clone()) {
@ -891,7 +892,7 @@ fn args(p: &mut Parser) -> ParseResult {
});
}
while p.peek_direct() == Some(&NodeKind::LeftBracket) {
while p.peek_direct() == Some(&SyntaxKind::LeftBracket) {
content_block(p);
}
});
@ -900,14 +901,14 @@ fn args(p: &mut Parser) -> ParseResult {
}
fn let_binding(p: &mut Parser) -> ParseResult {
p.perform(NodeKind::LetBinding, |p| {
p.assert(NodeKind::Let);
p.perform(SyntaxKind::LetBinding, |p| {
p.assert(SyntaxKind::Let);
let marker = p.marker();
ident(p)?;
// If a parenthesis follows, this is a function definition.
let has_params = p.peek_direct() == Some(&NodeKind::LeftParen);
let has_params = p.peek_direct() == Some(&SyntaxKind::LeftParen);
if has_params {
let marker = p.marker();
p.start_group(Group::Paren);
@ -916,7 +917,7 @@ fn let_binding(p: &mut Parser) -> ParseResult {
params(p, marker);
}
if p.eat_if(NodeKind::Eq) {
if p.eat_if(SyntaxKind::Eq) {
expr(p)?;
} else if has_params {
// Function definitions must have a body.
@ -925,7 +926,7 @@ fn let_binding(p: &mut Parser) -> ParseResult {
// Rewrite into a closure expression if it's a function definition.
if has_params {
marker.end(p, NodeKind::Closure);
marker.end(p, SyntaxKind::Closure);
}
Ok(())
@ -933,11 +934,11 @@ fn let_binding(p: &mut Parser) -> ParseResult {
}
fn set_rule(p: &mut Parser) -> ParseResult {
p.perform(NodeKind::SetRule, |p| {
p.assert(NodeKind::Set);
p.perform(SyntaxKind::SetRule, |p| {
p.assert(SyntaxKind::Set);
ident(p)?;
args(p)?;
if p.eat_if(NodeKind::If) {
if p.eat_if(SyntaxKind::If) {
expr(p)?;
}
Ok(())
@ -945,10 +946,10 @@ fn set_rule(p: &mut Parser) -> ParseResult {
}
fn show_rule(p: &mut Parser) -> ParseResult {
p.perform(NodeKind::ShowRule, |p| {
p.assert(NodeKind::Show);
p.perform(SyntaxKind::ShowRule, |p| {
p.assert(SyntaxKind::Show);
expr(p)?;
if p.eat_if(NodeKind::Colon) {
if p.eat_if(SyntaxKind::Colon) {
expr(p)?;
}
Ok(())
@ -956,14 +957,14 @@ fn show_rule(p: &mut Parser) -> ParseResult {
}
fn conditional(p: &mut Parser) -> ParseResult {
p.perform(NodeKind::Conditional, |p| {
p.assert(NodeKind::If);
p.perform(SyntaxKind::Conditional, |p| {
p.assert(SyntaxKind::If);
expr(p)?;
body(p)?;
if p.eat_if(NodeKind::Else) {
if p.at(NodeKind::If) {
if p.eat_if(SyntaxKind::Else) {
if p.at(SyntaxKind::If) {
conditional(p)?;
} else {
body(p)?;
@ -975,27 +976,27 @@ fn conditional(p: &mut Parser) -> ParseResult {
}
fn while_loop(p: &mut Parser) -> ParseResult {
p.perform(NodeKind::WhileLoop, |p| {
p.assert(NodeKind::While);
p.perform(SyntaxKind::WhileLoop, |p| {
p.assert(SyntaxKind::While);
expr(p)?;
body(p)
})
}
fn for_loop(p: &mut Parser) -> ParseResult {
p.perform(NodeKind::ForLoop, |p| {
p.assert(NodeKind::For);
p.perform(SyntaxKind::ForLoop, |p| {
p.assert(SyntaxKind::For);
for_pattern(p)?;
p.expect(NodeKind::In)?;
p.expect(SyntaxKind::In)?;
expr(p)?;
body(p)
})
}
fn for_pattern(p: &mut Parser) -> ParseResult {
p.perform(NodeKind::ForPattern, |p| {
p.perform(SyntaxKind::ForPattern, |p| {
ident(p)?;
if p.eat_if(NodeKind::Comma) {
if p.eat_if(SyntaxKind::Comma) {
ident(p)?;
}
Ok(())
@ -1003,12 +1004,12 @@ fn for_pattern(p: &mut Parser) -> ParseResult {
}
fn module_import(p: &mut Parser) -> ParseResult {
p.perform(NodeKind::ModuleImport, |p| {
p.assert(NodeKind::Import);
p.perform(SyntaxKind::ModuleImport, |p| {
p.assert(SyntaxKind::Import);
if !p.eat_if(NodeKind::Star) {
if !p.eat_if(SyntaxKind::Star) {
// This is the list of identifiers scenario.
p.perform(NodeKind::ImportItems, |p| {
p.perform(SyntaxKind::ImportItems, |p| {
p.start_group(Group::Imports);
let marker = p.marker();
let items = collection(p, false).1;
@ -1018,42 +1019,42 @@ fn module_import(p: &mut Parser) -> ParseResult {
p.end_group();
marker.filter_children(p, |n| match n.kind() {
NodeKind::Ident(_) | NodeKind::Comma => Ok(()),
SyntaxKind::Ident(_) | SyntaxKind::Comma => Ok(()),
_ => Err("expected identifier"),
});
});
};
p.expect(NodeKind::From)?;
p.expect(SyntaxKind::From)?;
expr(p)
})
}
fn module_include(p: &mut Parser) -> ParseResult {
p.perform(NodeKind::ModuleInclude, |p| {
p.assert(NodeKind::Include);
p.perform(SyntaxKind::ModuleInclude, |p| {
p.assert(SyntaxKind::Include);
expr(p)
})
}
fn break_stmt(p: &mut Parser) -> ParseResult {
p.perform(NodeKind::LoopBreak, |p| {
p.assert(NodeKind::Break);
p.perform(SyntaxKind::LoopBreak, |p| {
p.assert(SyntaxKind::Break);
Ok(())
})
}
fn continue_stmt(p: &mut Parser) -> ParseResult {
p.perform(NodeKind::LoopContinue, |p| {
p.assert(NodeKind::Continue);
p.perform(SyntaxKind::LoopContinue, |p| {
p.assert(SyntaxKind::Continue);
Ok(())
})
}
fn return_stmt(p: &mut Parser) -> ParseResult {
p.perform(NodeKind::FuncReturn, |p| {
p.assert(NodeKind::Return);
if !p.at(NodeKind::Comma) && !p.eof() {
p.perform(SyntaxKind::FuncReturn, |p| {
p.assert(SyntaxKind::Return);
if !p.at(SyntaxKind::Comma) && !p.eof() {
expr(p)?;
}
Ok(())
@ -1062,8 +1063,8 @@ fn return_stmt(p: &mut Parser) -> ParseResult {
fn body(p: &mut Parser) -> ParseResult {
match p.peek() {
Some(NodeKind::LeftBracket) => Ok(content_block(p)),
Some(NodeKind::LeftBrace) => Ok(code_block(p)),
Some(SyntaxKind::LeftBracket) => Ok(content_block(p)),
Some(SyntaxKind::LeftBrace) => Ok(code_block(p)),
_ => {
p.expected("body");
Err(ParseError)

View File

@ -1,9 +1,79 @@
use std::fmt::{self, Debug, Display, Formatter};
use std::fmt::{self, Debug, Formatter};
use std::num::NonZeroU64;
use std::ops::Range;
use super::SourceId;
/// A unique identifier for a syntax node.
///
/// This is used throughout the compiler to track which source section an error
/// or element stems from. Can be [mapped back](super::Source::range) to a byte
/// range for user facing display.
///
/// During editing, the span values stay mostly stable, even for nodes behind an
/// insertion. This is not true for simple ranges as they would shift. Spans can
/// be used as inputs to memoized functions without hurting cache performance
/// when text is inserted somewhere in the document other than the end.
///
/// Span ids are ordered in the syntax tree to enable quickly finding the node
/// with some id:
/// - The id of a parent is always smaller than the ids of any of its children.
/// - The id of a node is always greater than any id in the subtrees of any left
/// sibling and smaller than any id in the subtrees of any right sibling.
///
/// This type takes up 8 bytes and is null-optimized (i.e. `Option<Span>` also
/// takes 8 bytes).
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Span(NonZeroU64);
impl Span {
// Data layout:
// | 16 bits source id | 48 bits number |
// Number of bits for and minimum and maximum numbers assignable to spans.
const BITS: usize = 48;
const DETACHED: u64 = 1;
/// The full range of numbers available for span numbering.
pub const FULL: Range<u64> = 2..(1 << Self::BITS);
/// Create a new span from a source id and a unique number.
///
/// Panics if the `number` is not contained in `FULL`.
pub const fn new(id: SourceId, number: u64) -> Self {
assert!(
Self::FULL.start <= number && number < Self::FULL.end,
"span number outside valid range"
);
let bits = ((id.into_u16() as u64) << Self::BITS) | number;
Self(to_non_zero(bits))
}
/// A span that does not point into any source file.
pub const fn detached() -> Self {
Self(to_non_zero(Self::DETACHED))
}
/// The id of the source file the span points into.
pub const fn source(self) -> SourceId {
SourceId::from_u16((self.0.get() >> Self::BITS) as u16)
}
/// The unique number of the span within its source file.
pub const fn number(self) -> u64 {
self.0.get() & ((1 << Self::BITS) - 1)
}
}
/// Convert to a non zero u64.
const fn to_non_zero(v: u64) -> NonZeroU64 {
match NonZeroU64::new(v) {
Some(v) => v,
None => panic!("span encoding is zero"),
}
}
/// A value with a span locating it in the source code.
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct Spanned<T> {
@ -39,91 +109,6 @@ impl<T: Debug> Debug for Spanned<T> {
}
}
/// A unique identifier for a syntax node.
///
/// This is used throughout the compiler to track which source section an error
/// or element stems from. Can be [mapped back](super::Source::range) to a byte
/// range for user facing display.
///
/// Span ids are ordered in the tree to enable quickly finding the node with
/// some id:
/// - The id of a parent is always smaller than the ids of any of its children.
/// - The id of a node is always greater than any id in the subtrees of any left
/// sibling and smaller than any id in the subtrees of any right sibling.
///
/// The internal ids of spans stay mostly stable, even for nodes behind an
/// insertion. This is not true for simple ranges as they would shift. Spans can
/// be used as inputs to memoized functions without hurting cache performance
/// when text is inserted somewhere in the document other than the end.
///
/// This type takes up 8 bytes and is null-optimized (i.e. `Option<Span>` also
/// takes 8 bytes).
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Span(NonZeroU64);
impl Span {
// Data layout:
// | 16 bits source id | 48 bits number |
// Number of bits for and minimum and maximum numbers assignable to spans.
const BITS: usize = 48;
const DETACHED: u64 = 1;
/// The full range of numbers available to spans.
pub const FULL: Range<u64> = 2..(1 << Self::BITS);
/// Create a new span from a source id and a unique number.
///
/// Panics if the `number` is not contained in `FULL`.
pub const fn new(id: SourceId, number: u64) -> Self {
assert!(
Self::FULL.start <= number && number < Self::FULL.end,
"span number outside valid range"
);
let bits = ((id.into_u16() as u64) << Self::BITS) | number;
Self(to_non_zero(bits))
}
/// A span that does not point into any source file.
pub const fn detached() -> Self {
Self(to_non_zero(Self::DETACHED))
}
/// The id of the source file the span points into.
pub const fn source(self) -> SourceId {
SourceId::from_u16((self.0.get() >> Self::BITS) as u16)
}
/// The unique number of the span within the source file.
pub const fn number(self) -> u64 {
self.0.get() & ((1 << Self::BITS) - 1)
}
}
/// Convert to a non zero u64.
const fn to_non_zero(v: u64) -> NonZeroU64 {
match NonZeroU64::new(v) {
Some(v) => v,
None => panic!("span encoding is zero"),
}
}
/// Result of numbering a node within an interval.
pub(super) type NumberingResult = Result<(), Unnumberable>;
/// Indicates that a node cannot be numbered within a given interval.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub(super) struct Unnumberable;
impl Display for Unnumberable {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.pad("cannot number within this interval")
}
}
impl std::error::Error for Unnumberable {}
#[cfg(test)]
mod tests {
use super::{SourceId, Span};

View File

@ -4,7 +4,7 @@ use unicode_xid::UnicodeXID;
use unscanny::Scanner;
use super::resolve::{resolve_hex, resolve_raw, resolve_string};
use super::{ErrorPos, NodeKind, RawFields, Unit};
use super::{ErrorPos, RawFields, SyntaxKind, Unit};
use crate::geom::{AbsUnit, AngleUnit};
use crate::util::{format_eco, EcoString};
@ -96,7 +96,7 @@ impl<'s> Tokens<'s> {
}
impl<'s> Iterator for Tokens<'s> {
type Item = NodeKind;
type Item = SyntaxKind;
/// Parse the next token in the source code.
#[inline]
@ -107,9 +107,10 @@ impl<'s> Iterator for Tokens<'s> {
// Trivia.
'/' if self.s.eat_if('/') => self.line_comment(),
'/' if self.s.eat_if('*') => self.block_comment(),
'*' if self.s.eat_if('/') => {
NodeKind::Error(ErrorPos::Full, "unexpected end of block comment".into())
}
'*' if self.s.eat_if('/') => SyntaxKind::Error(
ErrorPos::Full,
"unexpected end of block comment".into(),
),
c if c.is_whitespace() => self.whitespace(c),
// Other things.
@ -123,15 +124,15 @@ impl<'s> Iterator for Tokens<'s> {
}
impl<'s> Tokens<'s> {
fn line_comment(&mut self) -> NodeKind {
fn line_comment(&mut self) -> SyntaxKind {
self.s.eat_until(is_newline);
if self.s.peek().is_none() {
self.terminated = false;
}
NodeKind::LineComment
SyntaxKind::LineComment
}
fn block_comment(&mut self) -> NodeKind {
fn block_comment(&mut self) -> SyntaxKind {
let mut state = '_';
let mut depth = 1;
self.terminated = false;
@ -159,12 +160,12 @@ impl<'s> Tokens<'s> {
}
}
NodeKind::BlockComment
SyntaxKind::BlockComment
}
fn whitespace(&mut self, c: char) -> NodeKind {
fn whitespace(&mut self, c: char) -> SyntaxKind {
if c == ' ' && !self.s.at(char::is_whitespace) {
return NodeKind::Space { newlines: 0 };
return SyntaxKind::Space { newlines: 0 };
}
self.s.uneat();
@ -185,21 +186,21 @@ impl<'s> Tokens<'s> {
}
}
NodeKind::Space { newlines }
SyntaxKind::Space { newlines }
}
#[inline]
fn markup(&mut self, start: usize, c: char) -> NodeKind {
fn markup(&mut self, start: usize, c: char) -> SyntaxKind {
match c {
// Blocks.
'{' => NodeKind::LeftBrace,
'}' => NodeKind::RightBrace,
'[' => NodeKind::LeftBracket,
']' => NodeKind::RightBracket,
'{' => SyntaxKind::LeftBrace,
'}' => SyntaxKind::RightBrace,
'[' => SyntaxKind::LeftBracket,
']' => SyntaxKind::RightBracket,
// Multi-char things.
'#' => self.hash(start),
'.' if self.s.eat_if("..") => NodeKind::Shorthand('\u{2026}'),
'.' if self.s.eat_if("..") => SyntaxKind::Shorthand('\u{2026}'),
'-' => self.hyph(),
'h' if self.s.eat_if("ttp://") || self.s.eat_if("ttps://") => {
self.link(start)
@ -213,16 +214,16 @@ impl<'s> Tokens<'s> {
'\\' => self.backslash(),
// Single-char things.
'~' => NodeKind::Shorthand('\u{00A0}'),
'\'' => NodeKind::SmartQuote { double: false },
'"' => NodeKind::SmartQuote { double: true },
'*' if !self.in_word() => NodeKind::Star,
'_' if !self.in_word() => NodeKind::Underscore,
'$' => NodeKind::Dollar,
'=' => NodeKind::Eq,
'+' => NodeKind::Plus,
'/' => NodeKind::Slash,
':' => NodeKind::Colon,
'~' => SyntaxKind::Shorthand('\u{00A0}'),
'\'' => SyntaxKind::SmartQuote { double: false },
'"' => SyntaxKind::SmartQuote { double: true },
'*' if !self.in_word() => SyntaxKind::Star,
'_' if !self.in_word() => SyntaxKind::Underscore,
'$' => SyntaxKind::Dollar,
'=' => SyntaxKind::Eq,
'+' => SyntaxKind::Plus,
'/' => SyntaxKind::Slash,
':' => SyntaxKind::Colon,
// Plain text.
_ => self.text(start),
@ -230,7 +231,7 @@ impl<'s> Tokens<'s> {
}
#[inline]
fn text(&mut self, start: usize) -> NodeKind {
fn text(&mut self, start: usize) -> SyntaxKind {
macro_rules! table {
($(|$c:literal)*) => {{
let mut t = [false; 128];
@ -266,67 +267,67 @@ impl<'s> Tokens<'s> {
self.s = s;
}
NodeKind::Text(self.s.from(start).into())
SyntaxKind::Text(self.s.from(start).into())
}
fn backslash(&mut self) -> NodeKind {
fn backslash(&mut self) -> SyntaxKind {
match self.s.peek() {
Some('u') if self.s.eat_if("u{") => {
let sequence = self.s.eat_while(char::is_ascii_alphanumeric);
if self.s.eat_if('}') {
if let Some(c) = resolve_hex(sequence) {
NodeKind::Escape(c)
SyntaxKind::Escape(c)
} else {
NodeKind::Error(
SyntaxKind::Error(
ErrorPos::Full,
"invalid unicode escape sequence".into(),
)
}
} else {
self.terminated = false;
NodeKind::Error(ErrorPos::End, "expected closing brace".into())
SyntaxKind::Error(ErrorPos::End, "expected closing brace".into())
}
}
// Linebreaks.
Some(c) if c.is_whitespace() => NodeKind::Linebreak,
None => NodeKind::Linebreak,
Some(c) if c.is_whitespace() => SyntaxKind::Linebreak,
None => SyntaxKind::Linebreak,
// Escapes.
Some(c) => {
self.s.expect(c);
NodeKind::Escape(c)
SyntaxKind::Escape(c)
}
}
}
fn hash(&mut self, start: usize) -> NodeKind {
fn hash(&mut self, start: usize) -> SyntaxKind {
if self.s.at(is_id_start) {
let read = self.s.eat_while(is_id_continue);
match keyword(read) {
Some(keyword) => keyword,
None => NodeKind::Ident(read.into()),
None => SyntaxKind::Ident(read.into()),
}
} else {
self.text(start)
}
}
fn hyph(&mut self) -> NodeKind {
fn hyph(&mut self) -> SyntaxKind {
if self.s.eat_if('-') {
if self.s.eat_if('-') {
NodeKind::Shorthand('\u{2014}')
SyntaxKind::Shorthand('\u{2014}')
} else {
NodeKind::Shorthand('\u{2013}')
SyntaxKind::Shorthand('\u{2013}')
}
} else if self.s.eat_if('?') {
NodeKind::Shorthand('\u{00AD}')
SyntaxKind::Shorthand('\u{00AD}')
} else {
NodeKind::Minus
SyntaxKind::Minus
}
}
fn link(&mut self, start: usize) -> NodeKind {
fn link(&mut self, start: usize) -> SyntaxKind {
#[rustfmt::skip]
self.s.eat_while(|c: char| matches!(c,
| '0' ..= '9'
@ -338,10 +339,10 @@ impl<'s> Tokens<'s> {
if self.s.scout(-1) == Some('.') {
self.s.uneat();
}
NodeKind::Link(self.s.from(start).into())
SyntaxKind::Link(self.s.from(start).into())
}
fn raw(&mut self) -> NodeKind {
fn raw(&mut self) -> SyntaxKind {
let column = self.column(self.s.cursor() - 1);
let mut backticks = 1;
@ -351,7 +352,7 @@ impl<'s> Tokens<'s> {
// Special case for empty inline block.
if backticks == 2 {
return NodeKind::Raw(Arc::new(RawFields {
return SyntaxKind::Raw(Arc::new(RawFields {
text: EcoString::new(),
lang: None,
block: false,
@ -370,7 +371,7 @@ impl<'s> Tokens<'s> {
if found == backticks {
let end = self.s.cursor() - found as usize;
NodeKind::Raw(Arc::new(resolve_raw(
SyntaxKind::Raw(Arc::new(resolve_raw(
column,
backticks,
self.s.get(start..end),
@ -379,7 +380,7 @@ impl<'s> Tokens<'s> {
self.terminated = false;
let remaining = backticks - found;
let noun = if remaining == 1 { "backtick" } else { "backticks" };
NodeKind::Error(
SyntaxKind::Error(
ErrorPos::End,
if found == 0 {
format_eco!("expected {} {}", remaining, noun)
@ -390,114 +391,114 @@ impl<'s> Tokens<'s> {
}
}
fn numbering(&mut self, start: usize) -> NodeKind {
fn numbering(&mut self, start: usize) -> SyntaxKind {
self.s.eat_while(char::is_ascii_digit);
let read = self.s.from(start);
if self.s.eat_if('.') {
if let Ok(number) = read.parse() {
return NodeKind::EnumNumbering(number);
return SyntaxKind::EnumNumbering(number);
}
}
self.text(start)
}
fn label(&mut self) -> NodeKind {
fn label(&mut self) -> SyntaxKind {
let label = self.s.eat_while(is_id_continue);
if self.s.eat_if('>') {
if !label.is_empty() {
NodeKind::Label(label.into())
SyntaxKind::Label(label.into())
} else {
NodeKind::Error(ErrorPos::Full, "label cannot be empty".into())
SyntaxKind::Error(ErrorPos::Full, "label cannot be empty".into())
}
} else {
self.terminated = false;
NodeKind::Error(ErrorPos::End, "expected closing angle bracket".into())
SyntaxKind::Error(ErrorPos::End, "expected closing angle bracket".into())
}
}
fn reference(&mut self, start: usize) -> NodeKind {
fn reference(&mut self, start: usize) -> SyntaxKind {
let label = self.s.eat_while(is_id_continue);
if !label.is_empty() {
NodeKind::Ref(label.into())
SyntaxKind::Ref(label.into())
} else {
self.text(start)
}
}
fn math(&mut self, start: usize, c: char) -> NodeKind {
fn math(&mut self, start: usize, c: char) -> SyntaxKind {
match c {
// Escape sequences.
'\\' => self.backslash(),
// Single-char things.
'_' => NodeKind::Underscore,
'^' => NodeKind::Hat,
'/' => NodeKind::Slash,
'&' => NodeKind::Amp,
'$' => NodeKind::Dollar,
'_' => SyntaxKind::Underscore,
'^' => SyntaxKind::Hat,
'/' => SyntaxKind::Slash,
'&' => SyntaxKind::Amp,
'$' => SyntaxKind::Dollar,
// Brackets.
'{' => NodeKind::LeftBrace,
'}' => NodeKind::RightBrace,
'[' => NodeKind::LeftBracket,
']' => NodeKind::RightBracket,
'(' => NodeKind::LeftParen,
')' => NodeKind::RightParen,
'{' => SyntaxKind::LeftBrace,
'}' => SyntaxKind::RightBrace,
'[' => SyntaxKind::LeftBracket,
']' => SyntaxKind::RightBracket,
'(' => SyntaxKind::LeftParen,
')' => SyntaxKind::RightParen,
// Identifiers.
c if is_math_id_start(c) && self.s.at(is_math_id_continue) => {
self.s.eat_while(is_math_id_continue);
NodeKind::Ident(self.s.from(start).into())
SyntaxKind::Ident(self.s.from(start).into())
}
// Numbers.
c if c.is_numeric() => {
self.s.eat_while(char::is_numeric);
NodeKind::Atom(self.s.from(start).into())
SyntaxKind::Atom(self.s.from(start).into())
}
// Other math atoms.
c => NodeKind::Atom(c.into()),
c => SyntaxKind::Atom(c.into()),
}
}
fn code(&mut self, start: usize, c: char) -> NodeKind {
fn code(&mut self, start: usize, c: char) -> SyntaxKind {
match c {
// Blocks.
'{' => NodeKind::LeftBrace,
'}' => NodeKind::RightBrace,
'[' => NodeKind::LeftBracket,
']' => NodeKind::RightBracket,
'{' => SyntaxKind::LeftBrace,
'}' => SyntaxKind::RightBrace,
'[' => SyntaxKind::LeftBracket,
']' => SyntaxKind::RightBracket,
// Parentheses.
'(' => NodeKind::LeftParen,
')' => NodeKind::RightParen,
'(' => SyntaxKind::LeftParen,
')' => SyntaxKind::RightParen,
// Two-char operators.
'=' if self.s.eat_if('=') => NodeKind::EqEq,
'!' if self.s.eat_if('=') => NodeKind::ExclEq,
'<' if self.s.eat_if('=') => NodeKind::LtEq,
'>' if self.s.eat_if('=') => NodeKind::GtEq,
'+' if self.s.eat_if('=') => NodeKind::PlusEq,
'-' if self.s.eat_if('=') => NodeKind::HyphEq,
'*' if self.s.eat_if('=') => NodeKind::StarEq,
'/' if self.s.eat_if('=') => NodeKind::SlashEq,
'.' if self.s.eat_if('.') => NodeKind::Dots,
'=' if self.s.eat_if('>') => NodeKind::Arrow,
'=' if self.s.eat_if('=') => SyntaxKind::EqEq,
'!' if self.s.eat_if('=') => SyntaxKind::ExclEq,
'<' if self.s.eat_if('=') => SyntaxKind::LtEq,
'>' if self.s.eat_if('=') => SyntaxKind::GtEq,
'+' if self.s.eat_if('=') => SyntaxKind::PlusEq,
'-' if self.s.eat_if('=') => SyntaxKind::HyphEq,
'*' if self.s.eat_if('=') => SyntaxKind::StarEq,
'/' if self.s.eat_if('=') => SyntaxKind::SlashEq,
'.' if self.s.eat_if('.') => SyntaxKind::Dots,
'=' if self.s.eat_if('>') => SyntaxKind::Arrow,
// Single-char operators.
',' => NodeKind::Comma,
';' => NodeKind::Semicolon,
':' => NodeKind::Colon,
'+' => NodeKind::Plus,
'-' => NodeKind::Minus,
'*' => NodeKind::Star,
'/' => NodeKind::Slash,
'=' => NodeKind::Eq,
'<' => NodeKind::Lt,
'>' => NodeKind::Gt,
'.' if !self.s.at(char::is_ascii_digit) => NodeKind::Dot,
',' => SyntaxKind::Comma,
';' => SyntaxKind::Semicolon,
':' => SyntaxKind::Colon,
'+' => SyntaxKind::Plus,
'-' => SyntaxKind::Minus,
'*' => SyntaxKind::Star,
'/' => SyntaxKind::Slash,
'=' => SyntaxKind::Eq,
'<' => SyntaxKind::Lt,
'>' => SyntaxKind::Gt,
'.' if !self.s.at(char::is_ascii_digit) => SyntaxKind::Dot,
// Identifiers.
c if is_id_start(c) => self.ident(start),
@ -511,22 +512,22 @@ impl<'s> Tokens<'s> {
'"' => self.string(),
// Invalid token.
_ => NodeKind::Error(ErrorPos::Full, "not valid here".into()),
_ => SyntaxKind::Error(ErrorPos::Full, "not valid here".into()),
}
}
fn ident(&mut self, start: usize) -> NodeKind {
fn ident(&mut self, start: usize) -> SyntaxKind {
self.s.eat_while(is_id_continue);
match self.s.from(start) {
"none" => NodeKind::None,
"auto" => NodeKind::Auto,
"true" => NodeKind::Bool(true),
"false" => NodeKind::Bool(false),
id => keyword(id).unwrap_or_else(|| NodeKind::Ident(id.into())),
"none" => SyntaxKind::None,
"auto" => SyntaxKind::Auto,
"true" => SyntaxKind::Bool(true),
"false" => SyntaxKind::Bool(false),
id => keyword(id).unwrap_or_else(|| SyntaxKind::Ident(id.into())),
}
}
fn number(&mut self, start: usize, c: char) -> NodeKind {
fn number(&mut self, start: usize, c: char) -> SyntaxKind {
// Read the first part (integer or fractional depending on `first`).
self.s.eat_while(char::is_ascii_digit);
@ -554,30 +555,30 @@ impl<'s> Tokens<'s> {
// Find out whether it is a simple number.
if suffix.is_empty() {
if let Ok(i) = number.parse::<i64>() {
return NodeKind::Int(i);
return SyntaxKind::Int(i);
}
}
let Ok(v) = number.parse::<f64>() else {
return NodeKind::Error(ErrorPos::Full, "invalid number".into());
return SyntaxKind::Error(ErrorPos::Full, "invalid number".into());
};
match suffix {
"" => NodeKind::Float(v),
"pt" => NodeKind::Numeric(v, Unit::Length(AbsUnit::Pt)),
"mm" => NodeKind::Numeric(v, Unit::Length(AbsUnit::Mm)),
"cm" => NodeKind::Numeric(v, Unit::Length(AbsUnit::Cm)),
"in" => NodeKind::Numeric(v, Unit::Length(AbsUnit::In)),
"deg" => NodeKind::Numeric(v, Unit::Angle(AngleUnit::Deg)),
"rad" => NodeKind::Numeric(v, Unit::Angle(AngleUnit::Rad)),
"em" => NodeKind::Numeric(v, Unit::Em),
"fr" => NodeKind::Numeric(v, Unit::Fr),
"%" => NodeKind::Numeric(v, Unit::Percent),
_ => NodeKind::Error(ErrorPos::Full, "invalid number suffix".into()),
"" => SyntaxKind::Float(v),
"pt" => SyntaxKind::Numeric(v, Unit::Length(AbsUnit::Pt)),
"mm" => SyntaxKind::Numeric(v, Unit::Length(AbsUnit::Mm)),
"cm" => SyntaxKind::Numeric(v, Unit::Length(AbsUnit::Cm)),
"in" => SyntaxKind::Numeric(v, Unit::Length(AbsUnit::In)),
"deg" => SyntaxKind::Numeric(v, Unit::Angle(AngleUnit::Deg)),
"rad" => SyntaxKind::Numeric(v, Unit::Angle(AngleUnit::Rad)),
"em" => SyntaxKind::Numeric(v, Unit::Em),
"fr" => SyntaxKind::Numeric(v, Unit::Fr),
"%" => SyntaxKind::Numeric(v, Unit::Percent),
_ => SyntaxKind::Error(ErrorPos::Full, "invalid number suffix".into()),
}
}
fn string(&mut self) -> NodeKind {
fn string(&mut self) -> SyntaxKind {
let mut escaped = false;
let verbatim = self.s.eat_until(|c| {
if c == '"' && !escaped {
@ -590,10 +591,10 @@ impl<'s> Tokens<'s> {
let string = resolve_string(verbatim);
if self.s.eat_if('"') {
NodeKind::Str(string)
SyntaxKind::Str(string)
} else {
self.terminated = false;
NodeKind::Error(ErrorPos::End, "expected quote".into())
SyntaxKind::Error(ErrorPos::End, "expected quote".into())
}
}
@ -605,25 +606,25 @@ impl<'s> Tokens<'s> {
}
}
fn keyword(ident: &str) -> Option<NodeKind> {
fn keyword(ident: &str) -> Option<SyntaxKind> {
Some(match ident {
"not" => NodeKind::Not,
"and" => NodeKind::And,
"or" => NodeKind::Or,
"let" => NodeKind::Let,
"set" => NodeKind::Set,
"show" => NodeKind::Show,
"if" => NodeKind::If,
"else" => NodeKind::Else,
"for" => NodeKind::For,
"in" => NodeKind::In,
"while" => NodeKind::While,
"break" => NodeKind::Break,
"continue" => NodeKind::Continue,
"return" => NodeKind::Return,
"import" => NodeKind::Import,
"include" => NodeKind::Include,
"from" => NodeKind::From,
"not" => SyntaxKind::Not,
"and" => SyntaxKind::And,
"or" => SyntaxKind::Or,
"let" => SyntaxKind::Let,
"set" => SyntaxKind::Set,
"show" => SyntaxKind::Show,
"if" => SyntaxKind::If,
"else" => SyntaxKind::Else,
"for" => SyntaxKind::For,
"in" => SyntaxKind::In,
"while" => SyntaxKind::While,
"break" => SyntaxKind::Break,
"continue" => SyntaxKind::Continue,
"return" => SyntaxKind::Return,
"import" => SyntaxKind::Import,
"include" => SyntaxKind::Include,
"from" => SyntaxKind::From,
_ => return None,
})
}
@ -715,36 +716,36 @@ mod tests {
use super::*;
use ErrorPos::*;
use NodeKind::*;
use Option::None;
use SyntaxKind::*;
use TokenMode::{Code, Markup};
fn Space(newlines: usize) -> NodeKind {
NodeKind::Space { newlines }
fn Space(newlines: usize) -> SyntaxKind {
SyntaxKind::Space { newlines }
}
fn Raw(text: &str, lang: Option<&str>, block: bool) -> NodeKind {
NodeKind::Raw(Arc::new(RawFields {
fn Raw(text: &str, lang: Option<&str>, block: bool) -> SyntaxKind {
SyntaxKind::Raw(Arc::new(RawFields {
text: text.into(),
lang: lang.map(Into::into),
block,
}))
}
fn Str(string: &str) -> NodeKind {
NodeKind::Str(string.into())
fn Str(string: &str) -> SyntaxKind {
SyntaxKind::Str(string.into())
}
fn Text(string: &str) -> NodeKind {
NodeKind::Text(string.into())
fn Text(string: &str) -> SyntaxKind {
SyntaxKind::Text(string.into())
}
fn Ident(ident: &str) -> NodeKind {
NodeKind::Ident(ident.into())
fn Ident(ident: &str) -> SyntaxKind {
SyntaxKind::Ident(ident.into())
}
fn Error(pos: ErrorPos, message: &str) -> NodeKind {
NodeKind::Error(pos, message.into())
fn Error(pos: ErrorPos, message: &str) -> SyntaxKind {
SyntaxKind::Error(pos, message.into())
}
/// Building blocks for suffix testing.
@ -769,7 +770,7 @@ mod tests {
// - the suffix string
// - the resulting suffix NodeKind
fn suffixes(
) -> impl Iterator<Item = (char, Option<TokenMode>, &'static str, NodeKind)> {
) -> impl Iterator<Item = (char, Option<TokenMode>, &'static str, SyntaxKind)> {
[
// Whitespace suffixes.
(' ', None, " ", Space(0)),
@ -1089,7 +1090,7 @@ mod tests {
// Combined integers and floats.
let nums = ints.iter().map(|&(k, v)| (k, v as f64)).chain(floats);
let suffixes: &[(&str, fn(f64) -> NodeKind)] = &[
let suffixes: &[(&str, fn(f64) -> SyntaxKind)] = &[
("mm", |x| Numeric(x, Unit::Length(AbsUnit::Mm))),
("pt", |x| Numeric(x, Unit::Length(AbsUnit::Pt))),
("cm", |x| Numeric(x, Unit::Length(AbsUnit::Cm))),