mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
Rename two syntax types
This commit is contained in:
parent
2ce727fc95
commit
b476de87b7
@ -11,7 +11,7 @@ use super::{
|
|||||||
};
|
};
|
||||||
use crate::diag::{bail, error, At, SourceResult, StrResult, Trace, Tracepoint};
|
use crate::diag::{bail, error, At, SourceResult, StrResult, Trace, Tracepoint};
|
||||||
use crate::geom::{Abs, Angle, Em, Fr, Ratio};
|
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::syntax::{ast, SourceId, Span, Spanned, Unit};
|
||||||
use crate::util::{format_eco, EcoString};
|
use crate::util::{format_eco, EcoString};
|
||||||
use crate::World;
|
use crate::World;
|
||||||
|
@ -8,7 +8,7 @@ use super::{
|
|||||||
Args, Eval, Flow, Node, NodeId, Route, Scope, Scopes, Selector, StyleMap, Value, Vm,
|
Args, Eval, Flow, Node, NodeId, Route, Scope, Scopes, Selector, StyleMap, Value, Vm,
|
||||||
};
|
};
|
||||||
use crate::diag::{bail, SourceResult, StrResult};
|
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::syntax::{SourceId, Span, SyntaxNode};
|
||||||
use crate::util::EcoString;
|
use crate::util::EcoString;
|
||||||
use crate::World;
|
use crate::World;
|
||||||
|
@ -5,11 +5,11 @@
|
|||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use super::{NodeKind, RawFields, Span, SyntaxNode, Unit};
|
use super::{RawFields, Span, SyntaxKind, SyntaxNode, Unit};
|
||||||
use crate::util::EcoString;
|
use crate::util::EcoString;
|
||||||
|
|
||||||
/// A typed AST node.
|
/// A typed AST node.
|
||||||
pub trait TypedNode: Sized {
|
pub trait AstNode: Sized {
|
||||||
/// Convert a node into its typed variant.
|
/// Convert a node into its typed variant.
|
||||||
fn from_untyped(node: &SyntaxNode) -> Option<Self>;
|
fn from_untyped(node: &SyntaxNode) -> Option<Self>;
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ pub trait TypedNode: Sized {
|
|||||||
|
|
||||||
macro_rules! node {
|
macro_rules! node {
|
||||||
($(#[$attr:meta])* $name:ident) => {
|
($(#[$attr:meta])* $name:ident) => {
|
||||||
node!{ $(#[$attr])* $name: NodeKind::$name { .. } }
|
node!{ $(#[$attr])* $name: SyntaxKind::$name { .. } }
|
||||||
};
|
};
|
||||||
($(#[$attr:meta])* $name:ident: $variants:pat) => {
|
($(#[$attr:meta])* $name:ident: $variants:pat) => {
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
@ -32,7 +32,7 @@ macro_rules! node {
|
|||||||
$(#[$attr])*
|
$(#[$attr])*
|
||||||
pub struct $name(SyntaxNode);
|
pub struct $name(SyntaxNode);
|
||||||
|
|
||||||
impl TypedNode for $name {
|
impl AstNode for $name {
|
||||||
fn from_untyped(node: &SyntaxNode) -> Option<Self> {
|
fn from_untyped(node: &SyntaxNode) -> Option<Self> {
|
||||||
if matches!(node.kind(), $variants) {
|
if matches!(node.kind(), $variants) {
|
||||||
Some(Self(node.clone()))
|
Some(Self(node.clone()))
|
||||||
@ -62,7 +62,8 @@ impl Markup {
|
|||||||
.filter(move |node| {
|
.filter(move |node| {
|
||||||
// Ignore linebreak directly after statements without semicolons.
|
// Ignore linebreak directly after statements without semicolons.
|
||||||
let kind = node.kind();
|
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();
|
was_stmt = kind.is_stmt();
|
||||||
keep
|
keep
|
||||||
})
|
})
|
||||||
@ -112,26 +113,26 @@ pub enum MarkupNode {
|
|||||||
Expr(Expr),
|
Expr(Expr),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypedNode for MarkupNode {
|
impl AstNode for MarkupNode {
|
||||||
fn from_untyped(node: &SyntaxNode) -> Option<Self> {
|
fn from_untyped(node: &SyntaxNode) -> Option<Self> {
|
||||||
match node.kind() {
|
match node.kind() {
|
||||||
NodeKind::Space { .. } => node.cast().map(Self::Space),
|
SyntaxKind::Space { .. } => node.cast().map(Self::Space),
|
||||||
NodeKind::Linebreak => node.cast().map(Self::Linebreak),
|
SyntaxKind::Linebreak => node.cast().map(Self::Linebreak),
|
||||||
NodeKind::Text(_) => node.cast().map(Self::Text),
|
SyntaxKind::Text(_) => node.cast().map(Self::Text),
|
||||||
NodeKind::Escape(_) => node.cast().map(Self::Escape),
|
SyntaxKind::Escape(_) => node.cast().map(Self::Escape),
|
||||||
NodeKind::Shorthand(_) => node.cast().map(Self::Shorthand),
|
SyntaxKind::Shorthand(_) => node.cast().map(Self::Shorthand),
|
||||||
NodeKind::SmartQuote { .. } => node.cast().map(Self::SmartQuote),
|
SyntaxKind::SmartQuote { .. } => node.cast().map(Self::SmartQuote),
|
||||||
NodeKind::Strong => node.cast().map(Self::Strong),
|
SyntaxKind::Strong => node.cast().map(Self::Strong),
|
||||||
NodeKind::Emph => node.cast().map(Self::Emph),
|
SyntaxKind::Emph => node.cast().map(Self::Emph),
|
||||||
NodeKind::Raw(_) => node.cast().map(Self::Raw),
|
SyntaxKind::Raw(_) => node.cast().map(Self::Raw),
|
||||||
NodeKind::Link(_) => node.cast().map(Self::Link),
|
SyntaxKind::Link(_) => node.cast().map(Self::Link),
|
||||||
NodeKind::Label(_) => node.cast().map(Self::Label),
|
SyntaxKind::Label(_) => node.cast().map(Self::Label),
|
||||||
NodeKind::Ref(_) => node.cast().map(Self::Ref),
|
SyntaxKind::Ref(_) => node.cast().map(Self::Ref),
|
||||||
NodeKind::Heading => node.cast().map(Self::Heading),
|
SyntaxKind::Heading => node.cast().map(Self::Heading),
|
||||||
NodeKind::ListItem => node.cast().map(Self::List),
|
SyntaxKind::ListItem => node.cast().map(Self::List),
|
||||||
NodeKind::EnumItem => node.cast().map(Self::Enum),
|
SyntaxKind::EnumItem => node.cast().map(Self::Enum),
|
||||||
NodeKind::DescItem => node.cast().map(Self::Desc),
|
SyntaxKind::DescItem => node.cast().map(Self::Desc),
|
||||||
NodeKind::Math => node.cast().map(Self::Math),
|
SyntaxKind::Math => node.cast().map(Self::Math),
|
||||||
_ => node.cast().map(Self::Expr),
|
_ => node.cast().map(Self::Expr),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -169,7 +170,7 @@ impl Space {
|
|||||||
/// Get the number of newlines.
|
/// Get the number of newlines.
|
||||||
pub fn newlines(&self) -> usize {
|
pub fn newlines(&self) -> usize {
|
||||||
match self.0.kind() {
|
match self.0.kind() {
|
||||||
&NodeKind::Space { newlines } => newlines,
|
&SyntaxKind::Space { newlines } => newlines,
|
||||||
_ => panic!("space is of wrong kind"),
|
_ => panic!("space is of wrong kind"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -189,7 +190,7 @@ impl Text {
|
|||||||
/// Get the text.
|
/// Get the text.
|
||||||
pub fn get(&self) -> &EcoString {
|
pub fn get(&self) -> &EcoString {
|
||||||
match self.0.kind() {
|
match self.0.kind() {
|
||||||
NodeKind::Text(v) => v,
|
SyntaxKind::Text(v) => v,
|
||||||
_ => panic!("text is of wrong kind"),
|
_ => panic!("text is of wrong kind"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -204,7 +205,7 @@ impl Escape {
|
|||||||
/// Get the escaped character.
|
/// Get the escaped character.
|
||||||
pub fn get(&self) -> char {
|
pub fn get(&self) -> char {
|
||||||
match self.0.kind() {
|
match self.0.kind() {
|
||||||
&NodeKind::Escape(v) => v,
|
&SyntaxKind::Escape(v) => v,
|
||||||
_ => panic!("escape is of wrong kind"),
|
_ => panic!("escape is of wrong kind"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -220,7 +221,7 @@ impl Shorthand {
|
|||||||
/// Get the shorthanded character.
|
/// Get the shorthanded character.
|
||||||
pub fn get(&self) -> char {
|
pub fn get(&self) -> char {
|
||||||
match self.0.kind() {
|
match self.0.kind() {
|
||||||
&NodeKind::Shorthand(v) => v,
|
&SyntaxKind::Shorthand(v) => v,
|
||||||
_ => panic!("shorthand is of wrong kind"),
|
_ => panic!("shorthand is of wrong kind"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -235,7 +236,7 @@ impl SmartQuote {
|
|||||||
/// Whether this is a double quote.
|
/// Whether this is a double quote.
|
||||||
pub fn double(&self) -> bool {
|
pub fn double(&self) -> bool {
|
||||||
match self.0.kind() {
|
match self.0.kind() {
|
||||||
&NodeKind::SmartQuote { double } => double,
|
&SyntaxKind::SmartQuote { double } => double,
|
||||||
_ => panic!("smart quote is of wrong kind"),
|
_ => panic!("smart quote is of wrong kind"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -291,7 +292,7 @@ impl Raw {
|
|||||||
/// The raw fields.
|
/// The raw fields.
|
||||||
fn get(&self) -> &RawFields {
|
fn get(&self) -> &RawFields {
|
||||||
match self.0.kind() {
|
match self.0.kind() {
|
||||||
NodeKind::Raw(v) => v.as_ref(),
|
SyntaxKind::Raw(v) => v.as_ref(),
|
||||||
_ => panic!("raw is of wrong kind"),
|
_ => panic!("raw is of wrong kind"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -306,7 +307,7 @@ impl Link {
|
|||||||
/// Get the URL.
|
/// Get the URL.
|
||||||
pub fn url(&self) -> &EcoString {
|
pub fn url(&self) -> &EcoString {
|
||||||
match self.0.kind() {
|
match self.0.kind() {
|
||||||
NodeKind::Link(url) => url,
|
SyntaxKind::Link(url) => url,
|
||||||
_ => panic!("link is of wrong kind"),
|
_ => panic!("link is of wrong kind"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -321,7 +322,7 @@ impl Label {
|
|||||||
/// Get the label.
|
/// Get the label.
|
||||||
pub fn get(&self) -> &EcoString {
|
pub fn get(&self) -> &EcoString {
|
||||||
match self.0.kind() {
|
match self.0.kind() {
|
||||||
NodeKind::Label(v) => v,
|
SyntaxKind::Label(v) => v,
|
||||||
_ => panic!("label is of wrong kind"),
|
_ => panic!("label is of wrong kind"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -336,7 +337,7 @@ impl Ref {
|
|||||||
/// Get the target.
|
/// Get the target.
|
||||||
pub fn get(&self) -> &EcoString {
|
pub fn get(&self) -> &EcoString {
|
||||||
match self.0.kind() {
|
match self.0.kind() {
|
||||||
NodeKind::Ref(v) => v,
|
SyntaxKind::Ref(v) => v,
|
||||||
_ => panic!("reference is of wrong kind"),
|
_ => panic!("reference is of wrong kind"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -357,7 +358,7 @@ impl Heading {
|
|||||||
pub fn level(&self) -> NonZeroUsize {
|
pub fn level(&self) -> NonZeroUsize {
|
||||||
self.0
|
self.0
|
||||||
.children()
|
.children()
|
||||||
.filter(|n| n.kind() == &NodeKind::Eq)
|
.filter(|n| n.kind() == &SyntaxKind::Eq)
|
||||||
.count()
|
.count()
|
||||||
.try_into()
|
.try_into()
|
||||||
.expect("heading is missing equals sign")
|
.expect("heading is missing equals sign")
|
||||||
@ -385,7 +386,7 @@ impl EnumItem {
|
|||||||
/// The explicit numbering, if any: `23.`.
|
/// The explicit numbering, if any: `23.`.
|
||||||
pub fn number(&self) -> Option<usize> {
|
pub fn number(&self) -> Option<usize> {
|
||||||
self.0.children().find_map(|node| match node.kind() {
|
self.0.children().find_map(|node| match node.kind() {
|
||||||
NodeKind::EnumNumbering(num) => Some(*num),
|
SyntaxKind::EnumNumbering(num) => Some(*num),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -458,17 +459,17 @@ pub enum MathNode {
|
|||||||
Expr(Expr),
|
Expr(Expr),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypedNode for MathNode {
|
impl AstNode for MathNode {
|
||||||
fn from_untyped(node: &SyntaxNode) -> Option<Self> {
|
fn from_untyped(node: &SyntaxNode) -> Option<Self> {
|
||||||
match node.kind() {
|
match node.kind() {
|
||||||
NodeKind::Space { .. } => node.cast().map(Self::Space),
|
SyntaxKind::Space { .. } => node.cast().map(Self::Space),
|
||||||
NodeKind::Linebreak => node.cast().map(Self::Linebreak),
|
SyntaxKind::Linebreak => node.cast().map(Self::Linebreak),
|
||||||
NodeKind::Escape(_) => node.cast().map(Self::Escape),
|
SyntaxKind::Escape(_) => node.cast().map(Self::Escape),
|
||||||
NodeKind::Atom(_) => node.cast().map(Self::Atom),
|
SyntaxKind::Atom(_) => node.cast().map(Self::Atom),
|
||||||
NodeKind::Script => node.cast().map(Self::Script),
|
SyntaxKind::Script => node.cast().map(Self::Script),
|
||||||
NodeKind::Frac => node.cast().map(Self::Frac),
|
SyntaxKind::Frac => node.cast().map(Self::Frac),
|
||||||
NodeKind::Align => node.cast().map(Self::Align),
|
SyntaxKind::Align => node.cast().map(Self::Align),
|
||||||
NodeKind::Math => node.cast().map(Self::Group),
|
SyntaxKind::Math => node.cast().map(Self::Group),
|
||||||
_ => node.cast().map(Self::Expr),
|
_ => node.cast().map(Self::Expr),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -497,7 +498,7 @@ impl Atom {
|
|||||||
/// Get the atom's text.
|
/// Get the atom's text.
|
||||||
pub fn get(&self) -> &EcoString {
|
pub fn get(&self) -> &EcoString {
|
||||||
match self.0.kind() {
|
match self.0.kind() {
|
||||||
NodeKind::Atom(v) => v,
|
SyntaxKind::Atom(v) => v,
|
||||||
_ => panic!("atom is of wrong kind"),
|
_ => panic!("atom is of wrong kind"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -518,7 +519,7 @@ impl Script {
|
|||||||
pub fn sub(&self) -> Option<MathNode> {
|
pub fn sub(&self) -> Option<MathNode> {
|
||||||
self.0
|
self.0
|
||||||
.children()
|
.children()
|
||||||
.skip_while(|node| !matches!(node.kind(), NodeKind::Underscore))
|
.skip_while(|node| !matches!(node.kind(), SyntaxKind::Underscore))
|
||||||
.nth(1)
|
.nth(1)
|
||||||
.map(|node| node.cast().expect("script node has invalid subscript"))
|
.map(|node| node.cast().expect("script node has invalid subscript"))
|
||||||
}
|
}
|
||||||
@ -527,7 +528,7 @@ impl Script {
|
|||||||
pub fn sup(&self) -> Option<MathNode> {
|
pub fn sup(&self) -> Option<MathNode> {
|
||||||
self.0
|
self.0
|
||||||
.children()
|
.children()
|
||||||
.skip_while(|node| !matches!(node.kind(), NodeKind::Hat))
|
.skip_while(|node| !matches!(node.kind(), SyntaxKind::Hat))
|
||||||
.nth(1)
|
.nth(1)
|
||||||
.map(|node| node.cast().expect("script node has invalid superscript"))
|
.map(|node| node.cast().expect("script node has invalid superscript"))
|
||||||
}
|
}
|
||||||
@ -558,7 +559,7 @@ node! {
|
|||||||
impl Align {
|
impl Align {
|
||||||
/// The number of ampersands.
|
/// The number of ampersands.
|
||||||
pub fn count(&self) -> usize {
|
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),
|
Return(FuncReturn),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypedNode for Expr {
|
impl AstNode for Expr {
|
||||||
fn from_untyped(node: &SyntaxNode) -> Option<Self> {
|
fn from_untyped(node: &SyntaxNode) -> Option<Self> {
|
||||||
match node.kind() {
|
match node.kind() {
|
||||||
NodeKind::Ident(_) => node.cast().map(Self::Ident),
|
SyntaxKind::Ident(_) => node.cast().map(Self::Ident),
|
||||||
NodeKind::CodeBlock => node.cast().map(Self::Code),
|
SyntaxKind::CodeBlock => node.cast().map(Self::Code),
|
||||||
NodeKind::ContentBlock => node.cast().map(Self::Content),
|
SyntaxKind::ContentBlock => node.cast().map(Self::Content),
|
||||||
NodeKind::Parenthesized => node.cast().map(Self::Parenthesized),
|
SyntaxKind::Parenthesized => node.cast().map(Self::Parenthesized),
|
||||||
NodeKind::Array => node.cast().map(Self::Array),
|
SyntaxKind::Array => node.cast().map(Self::Array),
|
||||||
NodeKind::Dict => node.cast().map(Self::Dict),
|
SyntaxKind::Dict => node.cast().map(Self::Dict),
|
||||||
NodeKind::Unary => node.cast().map(Self::Unary),
|
SyntaxKind::Unary => node.cast().map(Self::Unary),
|
||||||
NodeKind::Binary => node.cast().map(Self::Binary),
|
SyntaxKind::Binary => node.cast().map(Self::Binary),
|
||||||
NodeKind::FieldAccess => node.cast().map(Self::FieldAccess),
|
SyntaxKind::FieldAccess => node.cast().map(Self::FieldAccess),
|
||||||
NodeKind::FuncCall => node.cast().map(Self::FuncCall),
|
SyntaxKind::FuncCall => node.cast().map(Self::FuncCall),
|
||||||
NodeKind::MethodCall => node.cast().map(Self::MethodCall),
|
SyntaxKind::MethodCall => node.cast().map(Self::MethodCall),
|
||||||
NodeKind::Closure => node.cast().map(Self::Closure),
|
SyntaxKind::Closure => node.cast().map(Self::Closure),
|
||||||
NodeKind::LetBinding => node.cast().map(Self::Let),
|
SyntaxKind::LetBinding => node.cast().map(Self::Let),
|
||||||
NodeKind::SetRule => node.cast().map(Self::Set),
|
SyntaxKind::SetRule => node.cast().map(Self::Set),
|
||||||
NodeKind::ShowRule => node.cast().map(Self::Show),
|
SyntaxKind::ShowRule => node.cast().map(Self::Show),
|
||||||
NodeKind::Conditional => node.cast().map(Self::Conditional),
|
SyntaxKind::Conditional => node.cast().map(Self::Conditional),
|
||||||
NodeKind::WhileLoop => node.cast().map(Self::While),
|
SyntaxKind::WhileLoop => node.cast().map(Self::While),
|
||||||
NodeKind::ForLoop => node.cast().map(Self::For),
|
SyntaxKind::ForLoop => node.cast().map(Self::For),
|
||||||
NodeKind::ModuleImport => node.cast().map(Self::Import),
|
SyntaxKind::ModuleImport => node.cast().map(Self::Import),
|
||||||
NodeKind::ModuleInclude => node.cast().map(Self::Include),
|
SyntaxKind::ModuleInclude => node.cast().map(Self::Include),
|
||||||
NodeKind::LoopBreak => node.cast().map(Self::Break),
|
SyntaxKind::LoopBreak => node.cast().map(Self::Break),
|
||||||
NodeKind::LoopContinue => node.cast().map(Self::Continue),
|
SyntaxKind::LoopContinue => node.cast().map(Self::Continue),
|
||||||
NodeKind::FuncReturn => node.cast().map(Self::Return),
|
SyntaxKind::FuncReturn => node.cast().map(Self::Return),
|
||||||
_ => node.cast().map(Self::Lit),
|
_ => node.cast().map(Self::Lit),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -696,26 +697,26 @@ impl Expr {
|
|||||||
|
|
||||||
node! {
|
node! {
|
||||||
/// A literal: `1`, `true`, ...
|
/// A literal: `1`, `true`, ...
|
||||||
Lit: NodeKind::None
|
Lit: SyntaxKind::None
|
||||||
| NodeKind::Auto
|
| SyntaxKind::Auto
|
||||||
| NodeKind::Bool(_)
|
| SyntaxKind::Bool(_)
|
||||||
| NodeKind::Int(_)
|
| SyntaxKind::Int(_)
|
||||||
| NodeKind::Float(_)
|
| SyntaxKind::Float(_)
|
||||||
| NodeKind::Numeric(_, _)
|
| SyntaxKind::Numeric(_, _)
|
||||||
| NodeKind::Str(_)
|
| SyntaxKind::Str(_)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Lit {
|
impl Lit {
|
||||||
/// The kind of literal.
|
/// The kind of literal.
|
||||||
pub fn kind(&self) -> LitKind {
|
pub fn kind(&self) -> LitKind {
|
||||||
match *self.0.kind() {
|
match *self.0.kind() {
|
||||||
NodeKind::None => LitKind::None,
|
SyntaxKind::None => LitKind::None,
|
||||||
NodeKind::Auto => LitKind::Auto,
|
SyntaxKind::Auto => LitKind::Auto,
|
||||||
NodeKind::Bool(v) => LitKind::Bool(v),
|
SyntaxKind::Bool(v) => LitKind::Bool(v),
|
||||||
NodeKind::Int(v) => LitKind::Int(v),
|
SyntaxKind::Int(v) => LitKind::Int(v),
|
||||||
NodeKind::Float(v) => LitKind::Float(v),
|
SyntaxKind::Float(v) => LitKind::Float(v),
|
||||||
NodeKind::Numeric(v, unit) => LitKind::Numeric(v, unit),
|
SyntaxKind::Numeric(v, unit) => LitKind::Numeric(v, unit),
|
||||||
NodeKind::Str(ref v) => LitKind::Str(v.clone()),
|
SyntaxKind::Str(ref v) => LitKind::Str(v.clone()),
|
||||||
_ => panic!("literal is of wrong kind"),
|
_ => panic!("literal is of wrong kind"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -799,10 +800,10 @@ pub enum ArrayItem {
|
|||||||
Spread(Expr),
|
Spread(Expr),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypedNode for ArrayItem {
|
impl AstNode for ArrayItem {
|
||||||
fn from_untyped(node: &SyntaxNode) -> Option<Self> {
|
fn from_untyped(node: &SyntaxNode) -> Option<Self> {
|
||||||
match node.kind() {
|
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),
|
_ => node.cast().map(Self::Pos),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -838,12 +839,12 @@ pub enum DictItem {
|
|||||||
Spread(Expr),
|
Spread(Expr),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypedNode for DictItem {
|
impl AstNode for DictItem {
|
||||||
fn from_untyped(node: &SyntaxNode) -> Option<Self> {
|
fn from_untyped(node: &SyntaxNode) -> Option<Self> {
|
||||||
match node.kind() {
|
match node.kind() {
|
||||||
NodeKind::Named => node.cast().map(Self::Named),
|
SyntaxKind::Named => node.cast().map(Self::Named),
|
||||||
NodeKind::Keyed => node.cast().map(Self::Keyed),
|
SyntaxKind::Keyed => node.cast().map(Self::Keyed),
|
||||||
NodeKind::Spread => node.cast_first_child().map(Self::Spread),
|
SyntaxKind::Spread => node.cast_first_child().map(Self::Spread),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -885,7 +886,7 @@ impl Keyed {
|
|||||||
self.0
|
self.0
|
||||||
.children()
|
.children()
|
||||||
.find_map(|node| match node.kind() {
|
.find_map(|node| match node.kind() {
|
||||||
NodeKind::Str(key) => Some(key.clone()),
|
SyntaxKind::Str(key) => Some(key.clone()),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.expect("keyed pair is missing key")
|
.expect("keyed pair is missing key")
|
||||||
@ -930,11 +931,11 @@ pub enum UnOp {
|
|||||||
|
|
||||||
impl UnOp {
|
impl UnOp {
|
||||||
/// Try to convert the token into a unary operation.
|
/// 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 {
|
Some(match token {
|
||||||
NodeKind::Plus => Self::Pos,
|
SyntaxKind::Plus => Self::Pos,
|
||||||
NodeKind::Minus => Self::Neg,
|
SyntaxKind::Minus => Self::Neg,
|
||||||
NodeKind::Not => Self::Not,
|
SyntaxKind::Not => Self::Not,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -969,11 +970,11 @@ impl Binary {
|
|||||||
self.0
|
self.0
|
||||||
.children()
|
.children()
|
||||||
.find_map(|node| match node.kind() {
|
.find_map(|node| match node.kind() {
|
||||||
NodeKind::Not => {
|
SyntaxKind::Not => {
|
||||||
not = true;
|
not = true;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
NodeKind::In if not => Some(BinOp::NotIn),
|
SyntaxKind::In if not => Some(BinOp::NotIn),
|
||||||
_ => BinOp::from_token(node.kind()),
|
_ => BinOp::from_token(node.kind()),
|
||||||
})
|
})
|
||||||
.expect("binary operation is missing operator")
|
.expect("binary operation is missing operator")
|
||||||
@ -1039,26 +1040,26 @@ pub enum BinOp {
|
|||||||
|
|
||||||
impl BinOp {
|
impl BinOp {
|
||||||
/// Try to convert the token into a binary operation.
|
/// 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 {
|
Some(match token {
|
||||||
NodeKind::Plus => Self::Add,
|
SyntaxKind::Plus => Self::Add,
|
||||||
NodeKind::Minus => Self::Sub,
|
SyntaxKind::Minus => Self::Sub,
|
||||||
NodeKind::Star => Self::Mul,
|
SyntaxKind::Star => Self::Mul,
|
||||||
NodeKind::Slash => Self::Div,
|
SyntaxKind::Slash => Self::Div,
|
||||||
NodeKind::And => Self::And,
|
SyntaxKind::And => Self::And,
|
||||||
NodeKind::Or => Self::Or,
|
SyntaxKind::Or => Self::Or,
|
||||||
NodeKind::EqEq => Self::Eq,
|
SyntaxKind::EqEq => Self::Eq,
|
||||||
NodeKind::ExclEq => Self::Neq,
|
SyntaxKind::ExclEq => Self::Neq,
|
||||||
NodeKind::Lt => Self::Lt,
|
SyntaxKind::Lt => Self::Lt,
|
||||||
NodeKind::LtEq => Self::Leq,
|
SyntaxKind::LtEq => Self::Leq,
|
||||||
NodeKind::Gt => Self::Gt,
|
SyntaxKind::Gt => Self::Gt,
|
||||||
NodeKind::GtEq => Self::Geq,
|
SyntaxKind::GtEq => Self::Geq,
|
||||||
NodeKind::Eq => Self::Assign,
|
SyntaxKind::Eq => Self::Assign,
|
||||||
NodeKind::In => Self::In,
|
SyntaxKind::In => Self::In,
|
||||||
NodeKind::PlusEq => Self::AddAssign,
|
SyntaxKind::PlusEq => Self::AddAssign,
|
||||||
NodeKind::HyphEq => Self::SubAssign,
|
SyntaxKind::HyphEq => Self::SubAssign,
|
||||||
NodeKind::StarEq => Self::MulAssign,
|
SyntaxKind::StarEq => Self::MulAssign,
|
||||||
NodeKind::SlashEq => Self::DivAssign,
|
SyntaxKind::SlashEq => Self::DivAssign,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1231,11 +1232,11 @@ pub enum Arg {
|
|||||||
Spread(Expr),
|
Spread(Expr),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypedNode for Arg {
|
impl AstNode for Arg {
|
||||||
fn from_untyped(node: &SyntaxNode) -> Option<Self> {
|
fn from_untyped(node: &SyntaxNode) -> Option<Self> {
|
||||||
match node.kind() {
|
match node.kind() {
|
||||||
NodeKind::Named => node.cast().map(Self::Named),
|
SyntaxKind::Named => node.cast().map(Self::Named),
|
||||||
NodeKind::Spread => node.cast_first_child().map(Self::Spread),
|
SyntaxKind::Spread => node.cast_first_child().map(Self::Spread),
|
||||||
_ => node.cast().map(Self::Pos),
|
_ => node.cast().map(Self::Pos),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1266,7 +1267,7 @@ impl Closure {
|
|||||||
pub fn params(&self) -> impl DoubleEndedIterator<Item = Param> + '_ {
|
pub fn params(&self) -> impl DoubleEndedIterator<Item = Param> + '_ {
|
||||||
self.0
|
self.0
|
||||||
.children()
|
.children()
|
||||||
.find(|x| x.kind() == &NodeKind::Params)
|
.find(|x| x.kind() == &SyntaxKind::Params)
|
||||||
.expect("closure is missing parameter list")
|
.expect("closure is missing parameter list")
|
||||||
.children()
|
.children()
|
||||||
.filter_map(SyntaxNode::cast)
|
.filter_map(SyntaxNode::cast)
|
||||||
@ -1289,12 +1290,12 @@ pub enum Param {
|
|||||||
Sink(Ident),
|
Sink(Ident),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypedNode for Param {
|
impl AstNode for Param {
|
||||||
fn from_untyped(node: &SyntaxNode) -> Option<Self> {
|
fn from_untyped(node: &SyntaxNode) -> Option<Self> {
|
||||||
match node.kind() {
|
match node.kind() {
|
||||||
NodeKind::Ident(_) => node.cast().map(Self::Pos),
|
SyntaxKind::Ident(_) => node.cast().map(Self::Pos),
|
||||||
NodeKind::Named => node.cast().map(Self::Named),
|
SyntaxKind::Named => node.cast().map(Self::Named),
|
||||||
NodeKind::Spread => node.cast_first_child().map(Self::Sink),
|
SyntaxKind::Spread => node.cast_first_child().map(Self::Sink),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1357,7 +1358,7 @@ impl SetRule {
|
|||||||
pub fn condition(&self) -> Option<Expr> {
|
pub fn condition(&self) -> Option<Expr> {
|
||||||
self.0
|
self.0
|
||||||
.children()
|
.children()
|
||||||
.skip_while(|child| child.kind() != &NodeKind::If)
|
.skip_while(|child| child.kind() != &SyntaxKind::If)
|
||||||
.find_map(SyntaxNode::cast)
|
.find_map(SyntaxNode::cast)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1373,7 +1374,7 @@ impl ShowRule {
|
|||||||
self.0
|
self.0
|
||||||
.children()
|
.children()
|
||||||
.rev()
|
.rev()
|
||||||
.skip_while(|child| child.kind() != &NodeKind::Colon)
|
.skip_while(|child| child.kind() != &SyntaxKind::Colon)
|
||||||
.find_map(SyntaxNode::cast)
|
.find_map(SyntaxNode::cast)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1482,8 +1483,8 @@ impl ModuleImport {
|
|||||||
self.0
|
self.0
|
||||||
.children()
|
.children()
|
||||||
.find_map(|node| match node.kind() {
|
.find_map(|node| match node.kind() {
|
||||||
NodeKind::Star => Some(Imports::Wildcard),
|
SyntaxKind::Star => Some(Imports::Wildcard),
|
||||||
NodeKind::ImportItems => {
|
SyntaxKind::ImportItems => {
|
||||||
let items = node.children().filter_map(SyntaxNode::cast).collect();
|
let items = node.children().filter_map(SyntaxNode::cast).collect();
|
||||||
Some(Imports::Items(items))
|
Some(Imports::Items(items))
|
||||||
}
|
}
|
||||||
@ -1550,7 +1551,7 @@ impl Ident {
|
|||||||
/// Get the identifier.
|
/// Get the identifier.
|
||||||
pub fn get(&self) -> &EcoString {
|
pub fn get(&self) -> &EcoString {
|
||||||
match self.0.kind() {
|
match self.0.kind() {
|
||||||
NodeKind::Ident(id) => id,
|
SyntaxKind::Ident(id) => id,
|
||||||
_ => panic!("identifier is of wrong kind"),
|
_ => panic!("identifier is of wrong kind"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1558,7 +1559,7 @@ impl Ident {
|
|||||||
/// Take out the container identifier.
|
/// Take out the container identifier.
|
||||||
pub fn take(self) -> EcoString {
|
pub fn take(self) -> EcoString {
|
||||||
match self.0.take() {
|
match self.0.take() {
|
||||||
NodeKind::Ident(id) => id,
|
SyntaxKind::Ident(id) => id,
|
||||||
_ => panic!("identifier is of wrong kind"),
|
_ => panic!("identifier is of wrong kind"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use std::ops::Range;
|
|||||||
use syntect::highlighting::{Color, FontStyle, Highlighter, Style, Theme};
|
use syntect::highlighting::{Color, FontStyle, Highlighter, Style, Theme};
|
||||||
use syntect::parsing::Scope;
|
use syntect::parsing::Scope;
|
||||||
|
|
||||||
use super::{parse, NodeKind, SyntaxNode};
|
use super::{parse, SyntaxKind, SyntaxNode};
|
||||||
|
|
||||||
/// Highlight source text into a standalone HTML document.
|
/// Highlight source text into a standalone HTML document.
|
||||||
pub fn highlight_html(text: &str, theme: &Theme) -> String {
|
pub fn highlight_html(text: &str, theme: &Theme) -> String {
|
||||||
@ -194,170 +194,170 @@ impl Category {
|
|||||||
i: usize,
|
i: usize,
|
||||||
) -> Option<Category> {
|
) -> Option<Category> {
|
||||||
match child.kind() {
|
match child.kind() {
|
||||||
NodeKind::LineComment => Some(Category::Comment),
|
SyntaxKind::LineComment => Some(Category::Comment),
|
||||||
NodeKind::BlockComment => Some(Category::Comment),
|
SyntaxKind::BlockComment => Some(Category::Comment),
|
||||||
NodeKind::Space { .. } => None,
|
SyntaxKind::Space { .. } => None,
|
||||||
|
|
||||||
NodeKind::LeftBrace => Some(Category::Bracket),
|
SyntaxKind::LeftBrace => Some(Category::Bracket),
|
||||||
NodeKind::RightBrace => Some(Category::Bracket),
|
SyntaxKind::RightBrace => Some(Category::Bracket),
|
||||||
NodeKind::LeftBracket => Some(Category::Bracket),
|
SyntaxKind::LeftBracket => Some(Category::Bracket),
|
||||||
NodeKind::RightBracket => Some(Category::Bracket),
|
SyntaxKind::RightBracket => Some(Category::Bracket),
|
||||||
NodeKind::LeftParen => Some(Category::Bracket),
|
SyntaxKind::LeftParen => Some(Category::Bracket),
|
||||||
NodeKind::RightParen => Some(Category::Bracket),
|
SyntaxKind::RightParen => Some(Category::Bracket),
|
||||||
NodeKind::Comma => Some(Category::Punctuation),
|
SyntaxKind::Comma => Some(Category::Punctuation),
|
||||||
NodeKind::Semicolon => Some(Category::Punctuation),
|
SyntaxKind::Semicolon => Some(Category::Punctuation),
|
||||||
NodeKind::Colon => Some(Category::Punctuation),
|
SyntaxKind::Colon => Some(Category::Punctuation),
|
||||||
NodeKind::Star => match parent.kind() {
|
SyntaxKind::Star => match parent.kind() {
|
||||||
NodeKind::Strong => None,
|
SyntaxKind::Strong => None,
|
||||||
_ => Some(Category::Operator),
|
_ => Some(Category::Operator),
|
||||||
},
|
},
|
||||||
NodeKind::Underscore => match parent.kind() {
|
SyntaxKind::Underscore => match parent.kind() {
|
||||||
NodeKind::Script => Some(Category::MathOperator),
|
SyntaxKind::Script => Some(Category::MathOperator),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
NodeKind::Dollar => Some(Category::MathDelimiter),
|
SyntaxKind::Dollar => Some(Category::MathDelimiter),
|
||||||
NodeKind::Plus => Some(match parent.kind() {
|
SyntaxKind::Plus => Some(match parent.kind() {
|
||||||
NodeKind::EnumItem => Category::ListMarker,
|
SyntaxKind::EnumItem => Category::ListMarker,
|
||||||
_ => Category::Operator,
|
_ => Category::Operator,
|
||||||
}),
|
}),
|
||||||
NodeKind::Minus => Some(match parent.kind() {
|
SyntaxKind::Minus => Some(match parent.kind() {
|
||||||
NodeKind::ListItem => Category::ListMarker,
|
SyntaxKind::ListItem => Category::ListMarker,
|
||||||
_ => Category::Operator,
|
_ => Category::Operator,
|
||||||
}),
|
}),
|
||||||
NodeKind::Slash => Some(match parent.kind() {
|
SyntaxKind::Slash => Some(match parent.kind() {
|
||||||
NodeKind::DescItem => Category::ListMarker,
|
SyntaxKind::DescItem => Category::ListMarker,
|
||||||
NodeKind::Frac => Category::MathOperator,
|
SyntaxKind::Frac => Category::MathOperator,
|
||||||
_ => Category::Operator,
|
_ => Category::Operator,
|
||||||
}),
|
}),
|
||||||
NodeKind::Hat => Some(Category::MathOperator),
|
SyntaxKind::Hat => Some(Category::MathOperator),
|
||||||
NodeKind::Amp => Some(Category::MathOperator),
|
SyntaxKind::Amp => Some(Category::MathOperator),
|
||||||
NodeKind::Dot => Some(Category::Punctuation),
|
SyntaxKind::Dot => Some(Category::Punctuation),
|
||||||
NodeKind::Eq => match parent.kind() {
|
SyntaxKind::Eq => match parent.kind() {
|
||||||
NodeKind::Heading => None,
|
SyntaxKind::Heading => None,
|
||||||
_ => Some(Category::Operator),
|
_ => Some(Category::Operator),
|
||||||
},
|
},
|
||||||
NodeKind::EqEq => Some(Category::Operator),
|
SyntaxKind::EqEq => Some(Category::Operator),
|
||||||
NodeKind::ExclEq => Some(Category::Operator),
|
SyntaxKind::ExclEq => Some(Category::Operator),
|
||||||
NodeKind::Lt => Some(Category::Operator),
|
SyntaxKind::Lt => Some(Category::Operator),
|
||||||
NodeKind::LtEq => Some(Category::Operator),
|
SyntaxKind::LtEq => Some(Category::Operator),
|
||||||
NodeKind::Gt => Some(Category::Operator),
|
SyntaxKind::Gt => Some(Category::Operator),
|
||||||
NodeKind::GtEq => Some(Category::Operator),
|
SyntaxKind::GtEq => Some(Category::Operator),
|
||||||
NodeKind::PlusEq => Some(Category::Operator),
|
SyntaxKind::PlusEq => Some(Category::Operator),
|
||||||
NodeKind::HyphEq => Some(Category::Operator),
|
SyntaxKind::HyphEq => Some(Category::Operator),
|
||||||
NodeKind::StarEq => Some(Category::Operator),
|
SyntaxKind::StarEq => Some(Category::Operator),
|
||||||
NodeKind::SlashEq => Some(Category::Operator),
|
SyntaxKind::SlashEq => Some(Category::Operator),
|
||||||
NodeKind::Dots => Some(Category::Operator),
|
SyntaxKind::Dots => Some(Category::Operator),
|
||||||
NodeKind::Arrow => Some(Category::Operator),
|
SyntaxKind::Arrow => Some(Category::Operator),
|
||||||
|
|
||||||
NodeKind::Not => Some(Category::Keyword),
|
SyntaxKind::Not => Some(Category::Keyword),
|
||||||
NodeKind::And => Some(Category::Keyword),
|
SyntaxKind::And => Some(Category::Keyword),
|
||||||
NodeKind::Or => Some(Category::Keyword),
|
SyntaxKind::Or => Some(Category::Keyword),
|
||||||
NodeKind::None => Some(Category::KeywordLiteral),
|
SyntaxKind::None => Some(Category::KeywordLiteral),
|
||||||
NodeKind::Auto => Some(Category::KeywordLiteral),
|
SyntaxKind::Auto => Some(Category::KeywordLiteral),
|
||||||
NodeKind::Let => Some(Category::Keyword),
|
SyntaxKind::Let => Some(Category::Keyword),
|
||||||
NodeKind::Set => Some(Category::Keyword),
|
SyntaxKind::Set => Some(Category::Keyword),
|
||||||
NodeKind::Show => Some(Category::Keyword),
|
SyntaxKind::Show => Some(Category::Keyword),
|
||||||
NodeKind::If => Some(Category::Keyword),
|
SyntaxKind::If => Some(Category::Keyword),
|
||||||
NodeKind::Else => Some(Category::Keyword),
|
SyntaxKind::Else => Some(Category::Keyword),
|
||||||
NodeKind::For => Some(Category::Keyword),
|
SyntaxKind::For => Some(Category::Keyword),
|
||||||
NodeKind::In => Some(Category::Keyword),
|
SyntaxKind::In => Some(Category::Keyword),
|
||||||
NodeKind::While => Some(Category::Keyword),
|
SyntaxKind::While => Some(Category::Keyword),
|
||||||
NodeKind::Break => Some(Category::Keyword),
|
SyntaxKind::Break => Some(Category::Keyword),
|
||||||
NodeKind::Continue => Some(Category::Keyword),
|
SyntaxKind::Continue => Some(Category::Keyword),
|
||||||
NodeKind::Return => Some(Category::Keyword),
|
SyntaxKind::Return => Some(Category::Keyword),
|
||||||
NodeKind::Import => Some(Category::Keyword),
|
SyntaxKind::Import => Some(Category::Keyword),
|
||||||
NodeKind::Include => Some(Category::Keyword),
|
SyntaxKind::Include => Some(Category::Keyword),
|
||||||
NodeKind::From => Some(Category::Keyword),
|
SyntaxKind::From => Some(Category::Keyword),
|
||||||
|
|
||||||
NodeKind::Markup { .. } => match parent.kind() {
|
SyntaxKind::Markup { .. } => match parent.kind() {
|
||||||
NodeKind::DescItem
|
SyntaxKind::DescItem
|
||||||
if parent
|
if parent
|
||||||
.children()
|
.children()
|
||||||
.take_while(|child| child.kind() != &NodeKind::Colon)
|
.take_while(|child| child.kind() != &SyntaxKind::Colon)
|
||||||
.find(|c| matches!(c.kind(), NodeKind::Markup { .. }))
|
.find(|c| matches!(c.kind(), SyntaxKind::Markup { .. }))
|
||||||
.map_or(false, |ident| std::ptr::eq(ident, child)) =>
|
.map_or(false, |ident| std::ptr::eq(ident, child)) =>
|
||||||
{
|
{
|
||||||
Some(Category::ListTerm)
|
Some(Category::ListTerm)
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
NodeKind::Text(_) => None,
|
SyntaxKind::Text(_) => None,
|
||||||
NodeKind::Linebreak => Some(Category::Escape),
|
SyntaxKind::Linebreak => Some(Category::Escape),
|
||||||
NodeKind::Escape(_) => Some(Category::Escape),
|
SyntaxKind::Escape(_) => Some(Category::Escape),
|
||||||
NodeKind::Shorthand(_) => Some(Category::Shorthand),
|
SyntaxKind::Shorthand(_) => Some(Category::Shorthand),
|
||||||
NodeKind::SmartQuote { .. } => Some(Category::SmartQuote),
|
SyntaxKind::SmartQuote { .. } => Some(Category::SmartQuote),
|
||||||
NodeKind::Strong => Some(Category::Strong),
|
SyntaxKind::Strong => Some(Category::Strong),
|
||||||
NodeKind::Emph => Some(Category::Emph),
|
SyntaxKind::Emph => Some(Category::Emph),
|
||||||
NodeKind::Raw(_) => Some(Category::Raw),
|
SyntaxKind::Raw(_) => Some(Category::Raw),
|
||||||
NodeKind::Link(_) => Some(Category::Link),
|
SyntaxKind::Link(_) => Some(Category::Link),
|
||||||
NodeKind::Label(_) => Some(Category::Label),
|
SyntaxKind::Label(_) => Some(Category::Label),
|
||||||
NodeKind::Ref(_) => Some(Category::Ref),
|
SyntaxKind::Ref(_) => Some(Category::Ref),
|
||||||
NodeKind::Heading => Some(Category::Heading),
|
SyntaxKind::Heading => Some(Category::Heading),
|
||||||
NodeKind::ListItem => Some(Category::ListItem),
|
SyntaxKind::ListItem => Some(Category::ListItem),
|
||||||
NodeKind::EnumItem => Some(Category::ListItem),
|
SyntaxKind::EnumItem => Some(Category::ListItem),
|
||||||
NodeKind::EnumNumbering(_) => Some(Category::ListMarker),
|
SyntaxKind::EnumNumbering(_) => Some(Category::ListMarker),
|
||||||
NodeKind::DescItem => Some(Category::ListItem),
|
SyntaxKind::DescItem => Some(Category::ListItem),
|
||||||
NodeKind::Math => Some(Category::Math),
|
SyntaxKind::Math => Some(Category::Math),
|
||||||
NodeKind::Atom(_) => None,
|
SyntaxKind::Atom(_) => None,
|
||||||
NodeKind::Script => None,
|
SyntaxKind::Script => None,
|
||||||
NodeKind::Frac => None,
|
SyntaxKind::Frac => None,
|
||||||
NodeKind::Align => None,
|
SyntaxKind::Align => None,
|
||||||
|
|
||||||
NodeKind::Ident(_) => match parent.kind() {
|
SyntaxKind::Ident(_) => match parent.kind() {
|
||||||
NodeKind::Markup { .. } => Some(Category::Interpolated),
|
SyntaxKind::Markup { .. } => Some(Category::Interpolated),
|
||||||
NodeKind::Math => Some(Category::Interpolated),
|
SyntaxKind::Math => Some(Category::Interpolated),
|
||||||
NodeKind::FuncCall => Some(Category::Function),
|
SyntaxKind::FuncCall => Some(Category::Function),
|
||||||
NodeKind::MethodCall if i > 0 => Some(Category::Function),
|
SyntaxKind::MethodCall if i > 0 => Some(Category::Function),
|
||||||
NodeKind::Closure if i == 0 => Some(Category::Function),
|
SyntaxKind::Closure if i == 0 => Some(Category::Function),
|
||||||
NodeKind::SetRule => Some(Category::Function),
|
SyntaxKind::SetRule => Some(Category::Function),
|
||||||
NodeKind::ShowRule
|
SyntaxKind::ShowRule
|
||||||
if parent
|
if parent
|
||||||
.children()
|
.children()
|
||||||
.rev()
|
.rev()
|
||||||
.skip_while(|child| child.kind() != &NodeKind::Colon)
|
.skip_while(|child| child.kind() != &SyntaxKind::Colon)
|
||||||
.find(|c| matches!(c.kind(), NodeKind::Ident(_)))
|
.find(|c| matches!(c.kind(), SyntaxKind::Ident(_)))
|
||||||
.map_or(false, |ident| std::ptr::eq(ident, child)) =>
|
.map_or(false, |ident| std::ptr::eq(ident, child)) =>
|
||||||
{
|
{
|
||||||
Some(Category::Function)
|
Some(Category::Function)
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
NodeKind::Bool(_) => Some(Category::KeywordLiteral),
|
SyntaxKind::Bool(_) => Some(Category::KeywordLiteral),
|
||||||
NodeKind::Int(_) => Some(Category::Number),
|
SyntaxKind::Int(_) => Some(Category::Number),
|
||||||
NodeKind::Float(_) => Some(Category::Number),
|
SyntaxKind::Float(_) => Some(Category::Number),
|
||||||
NodeKind::Numeric(_, _) => Some(Category::Number),
|
SyntaxKind::Numeric(_, _) => Some(Category::Number),
|
||||||
NodeKind::Str(_) => Some(Category::String),
|
SyntaxKind::Str(_) => Some(Category::String),
|
||||||
NodeKind::CodeBlock => None,
|
SyntaxKind::CodeBlock => None,
|
||||||
NodeKind::ContentBlock => None,
|
SyntaxKind::ContentBlock => None,
|
||||||
NodeKind::Parenthesized => None,
|
SyntaxKind::Parenthesized => None,
|
||||||
NodeKind::Array => None,
|
SyntaxKind::Array => None,
|
||||||
NodeKind::Dict => None,
|
SyntaxKind::Dict => None,
|
||||||
NodeKind::Named => None,
|
SyntaxKind::Named => None,
|
||||||
NodeKind::Keyed => None,
|
SyntaxKind::Keyed => None,
|
||||||
NodeKind::Unary => None,
|
SyntaxKind::Unary => None,
|
||||||
NodeKind::Binary => None,
|
SyntaxKind::Binary => None,
|
||||||
NodeKind::FieldAccess => None,
|
SyntaxKind::FieldAccess => None,
|
||||||
NodeKind::FuncCall => None,
|
SyntaxKind::FuncCall => None,
|
||||||
NodeKind::MethodCall => None,
|
SyntaxKind::MethodCall => None,
|
||||||
NodeKind::Args => None,
|
SyntaxKind::Args => None,
|
||||||
NodeKind::Spread => None,
|
SyntaxKind::Spread => None,
|
||||||
NodeKind::Closure => None,
|
SyntaxKind::Closure => None,
|
||||||
NodeKind::Params => None,
|
SyntaxKind::Params => None,
|
||||||
NodeKind::LetBinding => None,
|
SyntaxKind::LetBinding => None,
|
||||||
NodeKind::SetRule => None,
|
SyntaxKind::SetRule => None,
|
||||||
NodeKind::ShowRule => None,
|
SyntaxKind::ShowRule => None,
|
||||||
NodeKind::Conditional => None,
|
SyntaxKind::Conditional => None,
|
||||||
NodeKind::WhileLoop => None,
|
SyntaxKind::WhileLoop => None,
|
||||||
NodeKind::ForLoop => None,
|
SyntaxKind::ForLoop => None,
|
||||||
NodeKind::ForPattern => None,
|
SyntaxKind::ForPattern => None,
|
||||||
NodeKind::ModuleImport => None,
|
SyntaxKind::ModuleImport => None,
|
||||||
NodeKind::ImportItems => None,
|
SyntaxKind::ImportItems => None,
|
||||||
NodeKind::ModuleInclude => None,
|
SyntaxKind::ModuleInclude => None,
|
||||||
NodeKind::LoopBreak => None,
|
SyntaxKind::LoopBreak => None,
|
||||||
NodeKind::LoopContinue => None,
|
SyntaxKind::LoopContinue => None,
|
||||||
NodeKind::FuncReturn => None,
|
SyntaxKind::FuncReturn => None,
|
||||||
|
|
||||||
NodeKind::Error(_, _) => Some(Category::Error),
|
SyntaxKind::Error(_, _) => Some(Category::Error),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ use std::ops::Range;
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
is_newline, parse, reparse_code_block, reparse_content_block,
|
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.
|
/// Refresh the given syntax node with as little parsing as possible.
|
||||||
@ -36,7 +36,7 @@ fn try_reparse(
|
|||||||
outermost: bool,
|
outermost: bool,
|
||||||
safe_to_replace: bool,
|
safe_to_replace: bool,
|
||||||
) -> Option<Range<usize>> {
|
) -> 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_count = node.children().len();
|
||||||
let original_offset = offset;
|
let original_offset = offset;
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ fn try_reparse(
|
|||||||
} else {
|
} else {
|
||||||
// Update compulsary state of `ahead_nontrivia`.
|
// Update compulsary state of `ahead_nontrivia`.
|
||||||
if let Some(ahead_nontrivia) = ahead.as_mut() {
|
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();
|
ahead_nontrivia.newline();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,8 +87,8 @@ fn try_reparse(
|
|||||||
// reject text that points to the special case for URL
|
// reject text that points to the special case for URL
|
||||||
// evasion and line comments.
|
// evasion and line comments.
|
||||||
if !child.kind().is_space()
|
if !child.kind().is_space()
|
||||||
&& child.kind() != &NodeKind::Semicolon
|
&& child.kind() != &SyntaxKind::Semicolon
|
||||||
&& child.kind() != &NodeKind::Text('/'.into())
|
&& child.kind() != &SyntaxKind::Text('/'.into())
|
||||||
&& (ahead.is_none() || change.replaced.start > child_span.end)
|
&& (ahead.is_none() || change.replaced.start > child_span.end)
|
||||||
&& !ahead.map_or(false, Ahead::is_compulsory)
|
&& !ahead.map_or(false, Ahead::is_compulsory)
|
||||||
{
|
{
|
||||||
@ -153,8 +153,8 @@ fn try_reparse(
|
|||||||
|
|
||||||
let superseded_span = pos.offset..pos.offset + prev_len;
|
let superseded_span = pos.offset..pos.offset + prev_len;
|
||||||
let func: Option<ReparseMode> = match child.kind() {
|
let func: Option<ReparseMode> = match child.kind() {
|
||||||
NodeKind::CodeBlock => Some(ReparseMode::Code),
|
SyntaxKind::CodeBlock => Some(ReparseMode::Code),
|
||||||
NodeKind::ContentBlock => Some(ReparseMode::Content),
|
SyntaxKind::ContentBlock => Some(ReparseMode::Content),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -177,7 +177,7 @@ fn try_reparse(
|
|||||||
// Make sure this is a markup node and that we may replace. If so, save
|
// Make sure this is a markup node and that we may replace. If so, save
|
||||||
// the current indent.
|
// the current indent.
|
||||||
let min_indent = match node.kind() {
|
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,
|
_ => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -375,26 +375,28 @@ enum ReparseMode {
|
|||||||
|
|
||||||
/// Whether changes _inside_ this node are safely encapsulated, so that only
|
/// Whether changes _inside_ this node are safely encapsulated, so that only
|
||||||
/// this node must be reparsed.
|
/// this node must be reparsed.
|
||||||
fn is_bounded(kind: &NodeKind) -> bool {
|
fn is_bounded(kind: &SyntaxKind) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
kind,
|
kind,
|
||||||
NodeKind::CodeBlock
|
SyntaxKind::CodeBlock
|
||||||
| NodeKind::ContentBlock
|
| SyntaxKind::ContentBlock
|
||||||
| NodeKind::Linebreak
|
| SyntaxKind::Linebreak
|
||||||
| NodeKind::SmartQuote { .. }
|
| SyntaxKind::SmartQuote { .. }
|
||||||
| NodeKind::BlockComment
|
| SyntaxKind::BlockComment
|
||||||
| NodeKind::Space { .. }
|
| SyntaxKind::Space { .. }
|
||||||
| NodeKind::Escape(_)
|
| SyntaxKind::Escape(_)
|
||||||
| NodeKind::Shorthand(_)
|
| SyntaxKind::Shorthand(_)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether `at_start` would still be true after this node given the
|
/// Whether `at_start` would still be true after this node given the
|
||||||
/// previous value of the property.
|
/// 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 {
|
match kind {
|
||||||
NodeKind::Space { newlines: (1..) } => true,
|
SyntaxKind::Space { newlines: (1..) } => true,
|
||||||
NodeKind::Space { .. } | NodeKind::LineComment | NodeKind::BlockComment => prev,
|
SyntaxKind::Space { .. } | SyntaxKind::LineComment | SyntaxKind::BlockComment => {
|
||||||
|
prev
|
||||||
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,9 @@ use crate::util::EcoString;
|
|||||||
|
|
||||||
/// All syntactical building blocks that can be part of a Typst document.
|
/// 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
|
/// Can be created by the tokenizer or by the parser.
|
||||||
/// the parser.
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum NodeKind {
|
pub enum SyntaxKind {
|
||||||
/// A line comment: `// ...`.
|
/// A line comment: `// ...`.
|
||||||
LineComment,
|
LineComment,
|
||||||
/// A block comment: `/* ... */`.
|
/// A block comment: `/* ... */`.
|
||||||
@ -254,7 +253,7 @@ pub enum NodeKind {
|
|||||||
Error(ErrorPos, EcoString),
|
Error(ErrorPos, EcoString),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fields of a [`Raw`](NodeKind::Raw) node.
|
/// Fields of the raw syntax kind.
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub struct RawFields {
|
pub struct RawFields {
|
||||||
/// An optional identifier specifying the language to syntax-highlight in.
|
/// An optional identifier specifying the language to syntax-highlight in.
|
||||||
@ -293,7 +292,7 @@ pub enum ErrorPos {
|
|||||||
End,
|
End,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NodeKind {
|
impl SyntaxKind {
|
||||||
/// Whether this is trivia.
|
/// Whether this is trivia.
|
||||||
pub fn is_trivia(&self) -> bool {
|
pub fn is_trivia(&self) -> bool {
|
||||||
self.is_space() || matches!(self, Self::LineComment | Self::BlockComment)
|
self.is_space() || matches!(self, Self::LineComment | Self::BlockComment)
|
||||||
@ -311,18 +310,18 @@ impl NodeKind {
|
|||||||
|
|
||||||
/// Whether this is an error.
|
/// Whether this is an error.
|
||||||
pub fn is_error(&self) -> bool {
|
pub fn is_error(&self) -> bool {
|
||||||
matches!(self, NodeKind::Error(_, _))
|
matches!(self, SyntaxKind::Error(_, _))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Does this node need termination through a semicolon or linebreak?
|
/// Does this node need termination through a semicolon or linebreak?
|
||||||
pub fn is_stmt(&self) -> bool {
|
pub fn is_stmt(&self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
self,
|
self,
|
||||||
NodeKind::LetBinding
|
SyntaxKind::LetBinding
|
||||||
| NodeKind::SetRule
|
| SyntaxKind::SetRule
|
||||||
| NodeKind::ShowRule
|
| SyntaxKind::ShowRule
|
||||||
| NodeKind::ModuleImport
|
| SyntaxKind::ModuleImport
|
||||||
| NodeKind::ModuleInclude
|
| SyntaxKind::ModuleInclude
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,7 +444,7 @@ impl NodeKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for NodeKind {
|
impl Hash for SyntaxKind {
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
std::mem::discriminant(self).hash(state);
|
std::mem::discriminant(self).hash(state);
|
||||||
match self {
|
match self {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Display, Formatter};
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use super::ast::TypedNode;
|
use super::ast::AstNode;
|
||||||
use super::{NodeKind, NumberingResult, SourceId, Span, Unnumberable};
|
use super::{SourceId, Span, SyntaxKind};
|
||||||
use crate::diag::SourceError;
|
use crate::diag::SourceError;
|
||||||
|
|
||||||
/// A node in the untyped syntax tree.
|
/// A node in the untyped syntax tree.
|
||||||
@ -21,22 +21,22 @@ enum Repr {
|
|||||||
|
|
||||||
impl SyntaxNode {
|
impl SyntaxNode {
|
||||||
/// Create a new leaf node.
|
/// 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)))
|
Self(Repr::Leaf(NodeData::new(kind, len)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new inner node with children.
|
/// 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))))
|
Self(Repr::Inner(Arc::new(InnerNode::with_children(kind, children))))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The type of the node.
|
/// The type of the node.
|
||||||
pub fn kind(&self) -> &NodeKind {
|
pub fn kind(&self) -> &SyntaxKind {
|
||||||
&self.data().kind
|
&self.data().kind
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Take the kind out of the node.
|
/// Take the kind out of the node.
|
||||||
pub fn take(self) -> NodeKind {
|
pub fn take(self) -> SyntaxKind {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
Repr::Leaf(leaf) => leaf.kind,
|
Repr::Leaf(leaf) => leaf.kind,
|
||||||
Repr::Inner(inner) => inner.data.kind.clone(),
|
Repr::Inner(inner) => inner.data.kind.clone(),
|
||||||
@ -72,18 +72,18 @@ impl SyntaxNode {
|
|||||||
/// Convert the node to a typed AST node.
|
/// Convert the node to a typed AST node.
|
||||||
pub fn cast<T>(&self) -> Option<T>
|
pub fn cast<T>(&self) -> Option<T>
|
||||||
where
|
where
|
||||||
T: TypedNode,
|
T: AstNode,
|
||||||
{
|
{
|
||||||
T::from_untyped(self)
|
T::from_untyped(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the first child that can cast to the AST type `T`.
|
/// 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)
|
self.children().find_map(Self::cast)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the last child that can cast to the AST type `T`.
|
/// 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)
|
self.children().rev().find_map(Self::cast)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ impl SyntaxNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match self.kind() {
|
match self.kind() {
|
||||||
NodeKind::Error(pos, message) => {
|
SyntaxKind::Error(pos, message) => {
|
||||||
vec![SourceError::new(self.span(), message.clone()).with_pos(*pos)]
|
vec![SourceError::new(self.span(), message.clone()).with_pos(*pos)]
|
||||||
}
|
}
|
||||||
_ => self
|
_ => self
|
||||||
@ -114,7 +114,7 @@ impl SyntaxNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Change the type of the node.
|
/// 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 {
|
match &mut self.0 {
|
||||||
Repr::Inner(inner) => {
|
Repr::Inner(inner) => {
|
||||||
let node = Arc::make_mut(inner);
|
let node = Arc::make_mut(inner);
|
||||||
@ -226,7 +226,7 @@ impl Debug for SyntaxNode {
|
|||||||
|
|
||||||
impl Default for SyntaxNode {
|
impl Default for SyntaxNode {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::leaf(NodeKind::None, 0)
|
Self::leaf(SyntaxKind::None, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,7 +247,7 @@ struct InnerNode {
|
|||||||
|
|
||||||
impl InnerNode {
|
impl InnerNode {
|
||||||
/// Create a new inner node with the given kind and children.
|
/// 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 len = 0;
|
||||||
let mut descendants = 1;
|
let mut descendants = 1;
|
||||||
let mut erroneous = kind.is_error();
|
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;
|
let mut start = within.start;
|
||||||
if range.is_none() {
|
if range.is_none() {
|
||||||
let end = start + stride;
|
let end = start + stride;
|
||||||
@ -480,7 +480,7 @@ impl PartialEq for InnerNode {
|
|||||||
struct NodeData {
|
struct NodeData {
|
||||||
/// What kind of node this is (each kind would have its own struct in a
|
/// What kind of node this is (each kind would have its own struct in a
|
||||||
/// strongly typed AST).
|
/// strongly typed AST).
|
||||||
kind: NodeKind,
|
kind: SyntaxKind,
|
||||||
/// The byte length of the node in the source.
|
/// The byte length of the node in the source.
|
||||||
len: usize,
|
len: usize,
|
||||||
/// The node's span.
|
/// The node's span.
|
||||||
@ -489,7 +489,7 @@ struct NodeData {
|
|||||||
|
|
||||||
impl NodeData {
|
impl NodeData {
|
||||||
/// Create new node metadata.
|
/// Create new node metadata.
|
||||||
fn new(kind: NodeKind, len: usize) -> Self {
|
fn new(kind: SyntaxKind, len: usize) -> Self {
|
||||||
Self { len, kind, span: Span::detached() }
|
Self { len, kind, span: Span::detached() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -525,3 +525,18 @@ impl PartialEq for NodeData {
|
|||||||
self.kind == other.kind && self.len == other.len
|
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 {}
|
||||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use super::{ErrorPos, NodeKind, SyntaxNode, TokenMode, Tokens};
|
use super::{ErrorPos, SyntaxKind, SyntaxNode, TokenMode, Tokens};
|
||||||
use crate::util::{format_eco, EcoString};
|
use crate::util::{format_eco, EcoString};
|
||||||
|
|
||||||
/// A convenient token-based parser.
|
/// 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.
|
/// Whether we are at the end of the file or of a group.
|
||||||
eof: bool,
|
eof: bool,
|
||||||
/// The current token.
|
/// The current token.
|
||||||
current: Option<NodeKind>,
|
current: Option<SyntaxKind>,
|
||||||
/// The end byte index of the last non-trivia token.
|
/// The end byte index of the last non-trivia token.
|
||||||
prev_end: usize,
|
prev_end: usize,
|
||||||
/// The start byte index of the peeked token.
|
/// 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.
|
/// 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
|
where
|
||||||
F: FnOnce(&mut Self) -> T,
|
F: FnOnce(&mut Self) -> T,
|
||||||
{
|
{
|
||||||
@ -112,9 +112,9 @@ impl<'s> Parser<'s> {
|
|||||||
/// Consume the current token and also trailing trivia.
|
/// Consume the current token and also trailing trivia.
|
||||||
pub fn eat(&mut self) {
|
pub fn eat(&mut self) {
|
||||||
self.stray_terminator |= match self.current {
|
self.stray_terminator |= match self.current {
|
||||||
Some(NodeKind::RightParen) => !self.inside(Group::Paren),
|
Some(SyntaxKind::RightParen) => !self.inside(Group::Paren),
|
||||||
Some(NodeKind::RightBracket) => !self.inside(Group::Bracket),
|
Some(SyntaxKind::RightBracket) => !self.inside(Group::Bracket),
|
||||||
Some(NodeKind::RightBrace) => !self.inside(Group::Brace),
|
Some(SyntaxKind::RightBrace) => !self.inside(Group::Brace),
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -132,7 +132,7 @@ impl<'s> Parser<'s> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Consume the current token if it is the given one.
|
/// 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);
|
let at = self.at(kind);
|
||||||
if at {
|
if at {
|
||||||
self.eat();
|
self.eat();
|
||||||
@ -143,7 +143,7 @@ impl<'s> Parser<'s> {
|
|||||||
/// Eat tokens while the condition is true.
|
/// Eat tokens while the condition is true.
|
||||||
pub fn eat_while<F>(&mut self, mut f: F)
|
pub fn eat_while<F>(&mut self, mut f: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&NodeKind) -> bool,
|
F: FnMut(&SyntaxKind) -> bool,
|
||||||
{
|
{
|
||||||
while self.peek().map_or(false, |t| f(t)) {
|
while self.peek().map_or(false, |t| f(t)) {
|
||||||
self.eat();
|
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
|
/// Consume the current token if it is the given one and produce an error if
|
||||||
/// not.
|
/// not.
|
||||||
pub fn expect(&mut self, kind: NodeKind) -> ParseResult {
|
pub fn expect(&mut self, kind: SyntaxKind) -> ParseResult {
|
||||||
let at = self.peek() == Some(&kind);
|
let at = self.peek() == Some(&kind);
|
||||||
if at {
|
if at {
|
||||||
self.eat();
|
self.eat();
|
||||||
@ -165,18 +165,18 @@ impl<'s> Parser<'s> {
|
|||||||
|
|
||||||
/// Consume the current token, debug-asserting that it is the given one.
|
/// Consume the current token, debug-asserting that it is the given one.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn assert(&mut self, kind: NodeKind) {
|
pub fn assert(&mut self, kind: SyntaxKind) {
|
||||||
debug_assert_eq!(self.peek(), Some(&kind));
|
debug_assert_eq!(self.peek(), Some(&kind));
|
||||||
self.eat();
|
self.eat();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether the current token is of the given type.
|
/// 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)
|
self.peek() == Some(&kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Peek at the current token without consuming it.
|
/// Peek at the current token without consuming it.
|
||||||
pub fn peek(&self) -> Option<&NodeKind> {
|
pub fn peek(&self) -> Option<&SyntaxKind> {
|
||||||
if self.eof {
|
if self.eof {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
@ -186,7 +186,7 @@ impl<'s> Parser<'s> {
|
|||||||
|
|
||||||
/// Peek at the current token, but only if it follows immediately after the
|
/// Peek at the current token, but only if it follows immediately after the
|
||||||
/// last one without any trivia in between.
|
/// 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() {
|
if self.prev_end() == self.current_start() {
|
||||||
self.peek()
|
self.peek()
|
||||||
} else {
|
} else {
|
||||||
@ -249,12 +249,12 @@ impl<'s> Parser<'s> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
match kind {
|
match kind {
|
||||||
Group::Brace => self.assert(NodeKind::LeftBrace),
|
Group::Brace => self.assert(SyntaxKind::LeftBrace),
|
||||||
Group::Bracket => self.assert(NodeKind::LeftBracket),
|
Group::Bracket => self.assert(SyntaxKind::LeftBracket),
|
||||||
Group::Paren => self.assert(NodeKind::LeftParen),
|
Group::Paren => self.assert(SyntaxKind::LeftParen),
|
||||||
Group::Strong => self.assert(NodeKind::Star),
|
Group::Strong => self.assert(SyntaxKind::Star),
|
||||||
Group::Emph => self.assert(NodeKind::Underscore),
|
Group::Emph => self.assert(SyntaxKind::Underscore),
|
||||||
Group::Math => self.assert(NodeKind::Dollar),
|
Group::Math => self.assert(SyntaxKind::Dollar),
|
||||||
Group::Expr => self.repeek(),
|
Group::Expr => self.repeek(),
|
||||||
Group::Imports => self.repeek(),
|
Group::Imports => self.repeek(),
|
||||||
}
|
}
|
||||||
@ -273,13 +273,13 @@ impl<'s> Parser<'s> {
|
|||||||
|
|
||||||
// Eat the end delimiter if there is one.
|
// Eat the end delimiter if there is one.
|
||||||
if let Some((end, required)) = match group.kind {
|
if let Some((end, required)) = match group.kind {
|
||||||
Group::Brace => Some((NodeKind::RightBrace, true)),
|
Group::Brace => Some((SyntaxKind::RightBrace, true)),
|
||||||
Group::Bracket => Some((NodeKind::RightBracket, true)),
|
Group::Bracket => Some((SyntaxKind::RightBracket, true)),
|
||||||
Group::Paren => Some((NodeKind::RightParen, true)),
|
Group::Paren => Some((SyntaxKind::RightParen, true)),
|
||||||
Group::Strong => Some((NodeKind::Star, true)),
|
Group::Strong => Some((SyntaxKind::Star, true)),
|
||||||
Group::Emph => Some((NodeKind::Underscore, true)),
|
Group::Emph => Some((SyntaxKind::Underscore, true)),
|
||||||
Group::Math => Some((NodeKind::Dollar, true)),
|
Group::Math => Some((SyntaxKind::Dollar, true)),
|
||||||
Group::Expr => Some((NodeKind::Semicolon, false)),
|
Group::Expr => Some((SyntaxKind::Semicolon, false)),
|
||||||
Group::Imports => None,
|
Group::Imports => None,
|
||||||
} {
|
} {
|
||||||
if self.current.as_ref() == Some(&end) {
|
if self.current.as_ref() == Some(&end) {
|
||||||
@ -339,26 +339,26 @@ impl<'s> Parser<'s> {
|
|||||||
/// group.
|
/// group.
|
||||||
fn repeek(&mut self) {
|
fn repeek(&mut self) {
|
||||||
self.eof = match &self.current {
|
self.eof = match &self.current {
|
||||||
Some(NodeKind::RightBrace) => self.inside(Group::Brace),
|
Some(SyntaxKind::RightBrace) => self.inside(Group::Brace),
|
||||||
Some(NodeKind::RightBracket) => self.inside(Group::Bracket),
|
Some(SyntaxKind::RightBracket) => self.inside(Group::Bracket),
|
||||||
Some(NodeKind::RightParen) => self.inside(Group::Paren),
|
Some(SyntaxKind::RightParen) => self.inside(Group::Paren),
|
||||||
Some(NodeKind::Star) => self.inside(Group::Strong),
|
Some(SyntaxKind::Star) => self.inside(Group::Strong),
|
||||||
Some(NodeKind::Underscore) => self.inside(Group::Emph),
|
Some(SyntaxKind::Underscore) => self.inside(Group::Emph),
|
||||||
Some(NodeKind::Dollar) => self.inside(Group::Math),
|
Some(SyntaxKind::Dollar) => self.inside(Group::Math),
|
||||||
Some(NodeKind::Semicolon) => self.inside(Group::Expr),
|
Some(SyntaxKind::Semicolon) => self.inside(Group::Expr),
|
||||||
Some(NodeKind::From) => self.inside(Group::Imports),
|
Some(SyntaxKind::From) => self.inside(Group::Imports),
|
||||||
Some(NodeKind::Space { newlines }) => self.space_ends_group(*newlines),
|
Some(SyntaxKind::Space { newlines }) => self.space_ends_group(*newlines),
|
||||||
Some(_) => false,
|
Some(_) => false,
|
||||||
None => true,
|
None => true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the given type can be skipped over.
|
/// 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 {
|
match token {
|
||||||
NodeKind::Space { newlines } => !self.space_ends_group(*newlines),
|
SyntaxKind::Space { newlines } => !self.space_ends_group(*newlines),
|
||||||
NodeKind::LineComment => true,
|
SyntaxKind::LineComment => true,
|
||||||
NodeKind::BlockComment => true,
|
SyntaxKind::BlockComment => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -378,7 +378,7 @@ impl<'s> Parser<'s> {
|
|||||||
!= Some(Group::Brace)
|
!= Some(Group::Brace)
|
||||||
|| !matches!(
|
|| !matches!(
|
||||||
self.tokens.clone().next(),
|
self.tokens.clone().next(),
|
||||||
Some(NodeKind::Else | NodeKind::Dot)
|
Some(SyntaxKind::Else | SyntaxKind::Dot)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
@ -401,7 +401,7 @@ impl Parser<'_> {
|
|||||||
pub fn unexpected(&mut self) {
|
pub fn unexpected(&mut self) {
|
||||||
if let Some(found) = self.peek() {
|
if let Some(found) = self.peek() {
|
||||||
let msg = format_eco!("unexpected {}", found.name());
|
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);
|
self.perform(error, Self::eat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -415,7 +415,7 @@ impl Parser<'_> {
|
|||||||
/// Insert an error message that `what` was expected at the marker position.
|
/// Insert an error message that `what` was expected at the marker position.
|
||||||
pub fn expected_at(&mut self, marker: Marker, what: &str) {
|
pub fn expected_at(&mut self, marker: Marker, what: &str) {
|
||||||
let msg = format_eco!("expected {}", what);
|
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));
|
self.children.insert(marker.0, SyntaxNode::leaf(error, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -425,7 +425,7 @@ impl Parser<'_> {
|
|||||||
match self.peek() {
|
match self.peek() {
|
||||||
Some(found) => {
|
Some(found) => {
|
||||||
let msg = format_eco!("expected {}, found {}", thing, found.name());
|
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);
|
self.perform(error, Self::eat);
|
||||||
}
|
}
|
||||||
None => self.expected(thing),
|
None => self.expected(thing),
|
||||||
@ -449,7 +449,7 @@ impl Marker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Convert the child directly after 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) {
|
if let Some(child) = p.children.get_mut(self.0) {
|
||||||
child.convert(kind);
|
child.convert(kind);
|
||||||
}
|
}
|
||||||
@ -457,7 +457,7 @@ impl Marker {
|
|||||||
|
|
||||||
/// Perform a subparse that wraps all children after the marker in a node
|
/// Perform a subparse that wraps all children after the marker in a node
|
||||||
/// with the given kind.
|
/// 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
|
where
|
||||||
F: FnOnce(&mut Parser) -> T,
|
F: FnOnce(&mut Parser) -> T,
|
||||||
{
|
{
|
||||||
@ -468,7 +468,7 @@ impl Marker {
|
|||||||
|
|
||||||
/// Wrap all children after the marker (excluding trailing trivia) in a node
|
/// Wrap all children after the marker (excluding trailing trivia) in a node
|
||||||
/// with the given `kind`.
|
/// 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 until = p.trivia_start().0.max(self.0);
|
||||||
let children = p.children.drain(self.0..until).collect();
|
let children = p.children.drain(self.0..until).collect();
|
||||||
p.children.insert(self.0, SyntaxNode::inner(kind, children));
|
p.children.insert(self.0, SyntaxNode::inner(kind, children));
|
||||||
@ -496,7 +496,7 @@ impl Marker {
|
|||||||
msg.push_str(", found ");
|
msg.push_str(", found ");
|
||||||
msg.push_str(child.kind().name());
|
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);
|
let inner = mem::take(child);
|
||||||
*child = SyntaxNode::inner(error, vec![inner]);
|
*child = SyntaxNode::inner(error, vec![inner]);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use std::collections::HashSet;
|
|||||||
|
|
||||||
use super::ast::{Assoc, BinOp, UnOp};
|
use super::ast::{Assoc, BinOp, UnOp};
|
||||||
use super::{
|
use super::{
|
||||||
ErrorPos, Group, Marker, NodeKind, ParseError, ParseResult, Parser, SyntaxNode,
|
ErrorPos, Group, Marker, ParseError, ParseResult, Parser, SyntaxKind, SyntaxNode,
|
||||||
TokenMode,
|
TokenMode,
|
||||||
};
|
};
|
||||||
use crate::util::EcoString;
|
use crate::util::EcoString;
|
||||||
@ -17,7 +17,7 @@ pub fn parse(text: &str) -> SyntaxNode {
|
|||||||
/// Parse code directly, only used for syntax highlighting.
|
/// Parse code directly, only used for syntax highlighting.
|
||||||
pub fn parse_code(text: &str) -> SyntaxNode {
|
pub fn parse_code(text: &str) -> SyntaxNode {
|
||||||
let mut p = Parser::new(text, TokenMode::Code);
|
let mut p = Parser::new(text, TokenMode::Code);
|
||||||
p.perform(NodeKind::CodeBlock, code);
|
p.perform(SyntaxKind::CodeBlock, code);
|
||||||
p.finish().into_iter().next().unwrap()
|
p.finish().into_iter().next().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ pub(crate) fn reparse_code_block(
|
|||||||
end_pos: usize,
|
end_pos: usize,
|
||||||
) -> Option<(Vec<SyntaxNode>, bool, usize)> {
|
) -> Option<(Vec<SyntaxNode>, bool, usize)> {
|
||||||
let mut p = Parser::with_prefix(prefix, text, TokenMode::Code);
|
let mut p = Parser::with_prefix(prefix, text, TokenMode::Code);
|
||||||
if !p.at(NodeKind::LeftBrace) {
|
if !p.at(SyntaxKind::LeftBrace) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ pub(crate) fn reparse_content_block(
|
|||||||
end_pos: usize,
|
end_pos: usize,
|
||||||
) -> Option<(Vec<SyntaxNode>, bool, usize)> {
|
) -> Option<(Vec<SyntaxNode>, bool, usize)> {
|
||||||
let mut p = Parser::with_prefix(prefix, text, TokenMode::Code);
|
let mut p = Parser::with_prefix(prefix, text, TokenMode::Code);
|
||||||
if !p.at(NodeKind::LeftBracket) {
|
if !p.at(SyntaxKind::LeftBracket) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ pub(crate) fn reparse_markup_elements(
|
|||||||
let mut stopped = false;
|
let mut stopped = false;
|
||||||
|
|
||||||
'outer: while !p.eof() {
|
'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 {
|
if p.column(p.current_end()) < min_indent {
|
||||||
return None;
|
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
|
/// If `at_start` is true, things like headings that may only appear at the
|
||||||
/// beginning of a line or content block are initially allowed.
|
/// beginning of a line or content block are initially allowed.
|
||||||
fn markup(p: &mut Parser, mut at_start: bool) {
|
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() {
|
while !p.eof() {
|
||||||
markup_node(p, &mut at_start);
|
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`.
|
/// Parse markup that stays right of the given `column`.
|
||||||
fn markup_indented(p: &mut Parser, min_indent: usize) {
|
fn markup_indented(p: &mut Parser, min_indent: usize) {
|
||||||
p.eat_while(|t| match t {
|
p.eat_while(|t| match t {
|
||||||
NodeKind::Space { newlines } => *newlines == 0,
|
SyntaxKind::Space { newlines } => *newlines == 0,
|
||||||
NodeKind::LineComment | NodeKind::BlockComment => true,
|
SyntaxKind::LineComment | SyntaxKind::BlockComment => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -167,7 +167,7 @@ fn markup_indented(p: &mut Parser, min_indent: usize) {
|
|||||||
|
|
||||||
while !p.eof() {
|
while !p.eof() {
|
||||||
match p.peek() {
|
match p.peek() {
|
||||||
Some(NodeKind::Space { newlines: (1..) })
|
Some(SyntaxKind::Space { newlines: (1..) })
|
||||||
if p.column(p.current_end()) < min_indent =>
|
if p.column(p.current_end()) < min_indent =>
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
@ -178,24 +178,24 @@ fn markup_indented(p: &mut Parser, min_indent: usize) {
|
|||||||
markup_node(p, &mut at_start);
|
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.
|
/// Parse a line of markup that can prematurely end if `f` returns true.
|
||||||
fn markup_line<F>(p: &mut Parser, mut f: F)
|
fn markup_line<F>(p: &mut Parser, mut f: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&NodeKind) -> bool,
|
F: FnMut(&SyntaxKind) -> bool,
|
||||||
{
|
{
|
||||||
p.eat_while(|t| match t {
|
p.eat_while(|t| match t {
|
||||||
NodeKind::Space { newlines } => *newlines == 0,
|
SyntaxKind::Space { newlines } => *newlines == 0,
|
||||||
NodeKind::LineComment | NodeKind::BlockComment => true,
|
SyntaxKind::LineComment | SyntaxKind::BlockComment => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
});
|
});
|
||||||
|
|
||||||
p.perform(NodeKind::Markup { min_indent: usize::MAX }, |p| {
|
p.perform(SyntaxKind::Markup { min_indent: usize::MAX }, |p| {
|
||||||
let mut at_start = false;
|
let mut at_start = false;
|
||||||
while let Some(kind) = p.peek() {
|
while let Some(kind) = p.peek() {
|
||||||
if let NodeKind::Space { newlines: (1..) } = kind {
|
if let SyntaxKind::Space { newlines: (1..) } = kind {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,68 +212,68 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) {
|
|||||||
let Some(token) = p.peek() else { return };
|
let Some(token) = p.peek() else { return };
|
||||||
match token {
|
match token {
|
||||||
// Whitespace.
|
// Whitespace.
|
||||||
NodeKind::Space { newlines } => {
|
SyntaxKind::Space { newlines } => {
|
||||||
*at_start |= *newlines > 0;
|
*at_start |= *newlines > 0;
|
||||||
p.eat();
|
p.eat();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Comments.
|
// Comments.
|
||||||
NodeKind::LineComment | NodeKind::BlockComment => {
|
SyntaxKind::LineComment | SyntaxKind::BlockComment => {
|
||||||
p.eat();
|
p.eat();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Text and markup.
|
// Text and markup.
|
||||||
NodeKind::Text(_)
|
SyntaxKind::Text(_)
|
||||||
| NodeKind::Linebreak
|
| SyntaxKind::Linebreak
|
||||||
| NodeKind::SmartQuote { .. }
|
| SyntaxKind::SmartQuote { .. }
|
||||||
| NodeKind::Escape(_)
|
| SyntaxKind::Escape(_)
|
||||||
| NodeKind::Shorthand(_)
|
| SyntaxKind::Shorthand(_)
|
||||||
| NodeKind::Link(_)
|
| SyntaxKind::Link(_)
|
||||||
| NodeKind::Raw(_)
|
| SyntaxKind::Raw(_)
|
||||||
| NodeKind::Label(_)
|
| SyntaxKind::Label(_)
|
||||||
| NodeKind::Ref(_) => p.eat(),
|
| SyntaxKind::Ref(_) => p.eat(),
|
||||||
|
|
||||||
// Math.
|
// Math.
|
||||||
NodeKind::Dollar => math(p),
|
SyntaxKind::Dollar => math(p),
|
||||||
|
|
||||||
// Strong, emph, heading.
|
// Strong, emph, heading.
|
||||||
NodeKind::Star => strong(p),
|
SyntaxKind::Star => strong(p),
|
||||||
NodeKind::Underscore => emph(p),
|
SyntaxKind::Underscore => emph(p),
|
||||||
NodeKind::Eq => heading(p, *at_start),
|
SyntaxKind::Eq => heading(p, *at_start),
|
||||||
|
|
||||||
// Lists.
|
// Lists.
|
||||||
NodeKind::Minus => list_item(p, *at_start),
|
SyntaxKind::Minus => list_item(p, *at_start),
|
||||||
NodeKind::Plus | NodeKind::EnumNumbering(_) => enum_item(p, *at_start),
|
SyntaxKind::Plus | SyntaxKind::EnumNumbering(_) => enum_item(p, *at_start),
|
||||||
NodeKind::Slash => {
|
SyntaxKind::Slash => {
|
||||||
desc_item(p, *at_start).ok();
|
desc_item(p, *at_start).ok();
|
||||||
}
|
}
|
||||||
NodeKind::Colon => {
|
SyntaxKind::Colon => {
|
||||||
let marker = p.marker();
|
let marker = p.marker();
|
||||||
p.eat();
|
p.eat();
|
||||||
marker.convert(p, NodeKind::Text(':'.into()));
|
marker.convert(p, SyntaxKind::Text(':'.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hashtag + keyword / identifier.
|
// Hashtag + keyword / identifier.
|
||||||
NodeKind::Ident(_)
|
SyntaxKind::Ident(_)
|
||||||
| NodeKind::Let
|
| SyntaxKind::Let
|
||||||
| NodeKind::Set
|
| SyntaxKind::Set
|
||||||
| NodeKind::Show
|
| SyntaxKind::Show
|
||||||
| NodeKind::If
|
| SyntaxKind::If
|
||||||
| NodeKind::While
|
| SyntaxKind::While
|
||||||
| NodeKind::For
|
| SyntaxKind::For
|
||||||
| NodeKind::Import
|
| SyntaxKind::Import
|
||||||
| NodeKind::Include
|
| SyntaxKind::Include
|
||||||
| NodeKind::Break
|
| SyntaxKind::Break
|
||||||
| NodeKind::Continue
|
| SyntaxKind::Continue
|
||||||
| NodeKind::Return => markup_expr(p),
|
| SyntaxKind::Return => markup_expr(p),
|
||||||
|
|
||||||
// Code and content block.
|
// Code and content block.
|
||||||
NodeKind::LeftBrace => code_block(p),
|
SyntaxKind::LeftBrace => code_block(p),
|
||||||
NodeKind::LeftBracket => content_block(p),
|
SyntaxKind::LeftBracket => content_block(p),
|
||||||
|
|
||||||
NodeKind::Error(_, _) => p.eat(),
|
SyntaxKind::Error(_, _) => p.eat(),
|
||||||
_ => p.unexpected(),
|
_ => p.unexpected(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -281,7 +281,7 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn strong(p: &mut Parser) {
|
fn strong(p: &mut Parser) {
|
||||||
p.perform(NodeKind::Strong, |p| {
|
p.perform(SyntaxKind::Strong, |p| {
|
||||||
p.start_group(Group::Strong);
|
p.start_group(Group::Strong);
|
||||||
markup(p, false);
|
markup(p, false);
|
||||||
p.end_group();
|
p.end_group();
|
||||||
@ -289,7 +289,7 @@ fn strong(p: &mut Parser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn emph(p: &mut Parser) {
|
fn emph(p: &mut Parser) {
|
||||||
p.perform(NodeKind::Emph, |p| {
|
p.perform(SyntaxKind::Emph, |p| {
|
||||||
p.start_group(Group::Emph);
|
p.start_group(Group::Emph);
|
||||||
markup(p, false);
|
markup(p, false);
|
||||||
p.end_group();
|
p.end_group();
|
||||||
@ -299,30 +299,30 @@ fn emph(p: &mut Parser) {
|
|||||||
fn heading(p: &mut Parser, at_start: bool) {
|
fn heading(p: &mut Parser, at_start: bool) {
|
||||||
let marker = p.marker();
|
let marker = p.marker();
|
||||||
let current_start = p.current_start();
|
let current_start = p.current_start();
|
||||||
p.assert(NodeKind::Eq);
|
p.assert(SyntaxKind::Eq);
|
||||||
while p.eat_if(NodeKind::Eq) {}
|
while p.eat_if(SyntaxKind::Eq) {}
|
||||||
|
|
||||||
if at_start && p.peek().map_or(true, |kind| kind.is_space()) {
|
if at_start && p.peek().map_or(true, |kind| kind.is_space()) {
|
||||||
p.eat_while(|kind| *kind == NodeKind::Space { newlines: 0 });
|
p.eat_while(|kind| *kind == SyntaxKind::Space { newlines: 0 });
|
||||||
markup_line(p, |kind| matches!(kind, NodeKind::Label(_)));
|
markup_line(p, |kind| matches!(kind, SyntaxKind::Label(_)));
|
||||||
marker.end(p, NodeKind::Heading);
|
marker.end(p, SyntaxKind::Heading);
|
||||||
} else {
|
} else {
|
||||||
let text = p.get(current_start..p.prev_end()).into();
|
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) {
|
fn list_item(p: &mut Parser, at_start: bool) {
|
||||||
let marker = p.marker();
|
let marker = p.marker();
|
||||||
let text: EcoString = p.peek_src().into();
|
let text: EcoString = p.peek_src().into();
|
||||||
p.assert(NodeKind::Minus);
|
p.assert(SyntaxKind::Minus);
|
||||||
|
|
||||||
let min_indent = p.column(p.prev_end());
|
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);
|
markup_indented(p, min_indent);
|
||||||
marker.end(p, NodeKind::ListItem);
|
marker.end(p, SyntaxKind::ListItem);
|
||||||
} else {
|
} 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();
|
p.eat();
|
||||||
|
|
||||||
let min_indent = p.column(p.prev_end());
|
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);
|
markup_indented(p, min_indent);
|
||||||
marker.end(p, NodeKind::EnumItem);
|
marker.end(p, SyntaxKind::EnumItem);
|
||||||
} else {
|
} 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();
|
p.eat();
|
||||||
|
|
||||||
let min_indent = p.column(p.prev_end());
|
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_line(p, |node| matches!(node, NodeKind::Colon));
|
markup_line(p, |node| matches!(node, SyntaxKind::Colon));
|
||||||
p.expect(NodeKind::Colon)?;
|
p.expect(SyntaxKind::Colon)?;
|
||||||
markup_indented(p, min_indent);
|
markup_indented(p, min_indent);
|
||||||
marker.end(p, NodeKind::DescItem);
|
marker.end(p, SyntaxKind::DescItem);
|
||||||
} else {
|
} else {
|
||||||
marker.convert(p, NodeKind::Text(text));
|
marker.convert(p, SyntaxKind::Text(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -363,11 +363,11 @@ fn markup_expr(p: &mut Parser) {
|
|||||||
let stmt = matches!(
|
let stmt = matches!(
|
||||||
p.peek(),
|
p.peek(),
|
||||||
Some(
|
Some(
|
||||||
NodeKind::Let
|
SyntaxKind::Let
|
||||||
| NodeKind::Set
|
| SyntaxKind::Set
|
||||||
| NodeKind::Show
|
| SyntaxKind::Show
|
||||||
| NodeKind::Import
|
| SyntaxKind::Import
|
||||||
| NodeKind::Include
|
| SyntaxKind::Include
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -380,7 +380,7 @@ fn markup_expr(p: &mut Parser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn math(p: &mut Parser) {
|
fn math(p: &mut Parser) {
|
||||||
p.perform(NodeKind::Math, |p| {
|
p.perform(SyntaxKind::Math, |p| {
|
||||||
p.start_group(Group::Math);
|
p.start_group(Group::Math);
|
||||||
while !p.eof() {
|
while !p.eof() {
|
||||||
math_node(p);
|
math_node(p);
|
||||||
@ -393,20 +393,20 @@ fn math_node(p: &mut Parser) {
|
|||||||
math_node_prec(p, 0, None)
|
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();
|
let marker = p.marker();
|
||||||
math_primary(p);
|
math_primary(p);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let (kind, mut prec, assoc, stop) = match p.peek() {
|
let (kind, mut prec, assoc, stop) = match p.peek() {
|
||||||
v if v == stop.as_ref() => break,
|
v if v == stop.as_ref() => break,
|
||||||
Some(NodeKind::Underscore) => {
|
Some(SyntaxKind::Underscore) => {
|
||||||
(NodeKind::Script, 2, Assoc::Right, Some(NodeKind::Hat))
|
(SyntaxKind::Script, 2, Assoc::Right, Some(SyntaxKind::Hat))
|
||||||
}
|
}
|
||||||
Some(NodeKind::Hat) => {
|
Some(SyntaxKind::Hat) => {
|
||||||
(NodeKind::Script, 2, Assoc::Right, Some(NodeKind::Underscore))
|
(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,
|
_ => 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
|
// Allow up to two different scripts. We do not risk encountering the
|
||||||
// previous script kind again here due to right-associativity.
|
// 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);
|
math_node_prec(p, prec, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -437,42 +437,42 @@ fn math_primary(p: &mut Parser) {
|
|||||||
let Some(token) = p.peek() else { return };
|
let Some(token) = p.peek() else { return };
|
||||||
match token {
|
match token {
|
||||||
// Spaces, atoms and expressions.
|
// Spaces, atoms and expressions.
|
||||||
NodeKind::Space { .. }
|
SyntaxKind::Space { .. }
|
||||||
| NodeKind::Linebreak
|
| SyntaxKind::Linebreak
|
||||||
| NodeKind::Escape(_)
|
| SyntaxKind::Escape(_)
|
||||||
| NodeKind::Atom(_)
|
| SyntaxKind::Atom(_)
|
||||||
| NodeKind::Ident(_) => p.eat(),
|
| SyntaxKind::Ident(_) => p.eat(),
|
||||||
|
|
||||||
// Groups.
|
// Groups.
|
||||||
NodeKind::LeftParen => math_group(p, Group::Paren, '(', ')'),
|
SyntaxKind::LeftParen => math_group(p, Group::Paren, '(', ')'),
|
||||||
NodeKind::LeftBracket => math_group(p, Group::Bracket, '[', ']'),
|
SyntaxKind::LeftBracket => math_group(p, Group::Bracket, '[', ']'),
|
||||||
NodeKind::LeftBrace => math_group(p, Group::Brace, '{', '}'),
|
SyntaxKind::LeftBrace => math_group(p, Group::Brace, '{', '}'),
|
||||||
|
|
||||||
// Alignment indactor.
|
// Alignment indactor.
|
||||||
NodeKind::Amp => math_align(p),
|
SyntaxKind::Amp => math_align(p),
|
||||||
|
|
||||||
_ => p.unexpected(),
|
_ => p.unexpected(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn math_group(p: &mut Parser, group: Group, l: char, r: char) {
|
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();
|
let marker = p.marker();
|
||||||
p.start_group(group);
|
p.start_group(group);
|
||||||
marker.convert(p, NodeKind::Atom(l.into()));
|
marker.convert(p, SyntaxKind::Atom(l.into()));
|
||||||
while !p.eof() {
|
while !p.eof() {
|
||||||
math_node(p);
|
math_node(p);
|
||||||
}
|
}
|
||||||
let marker = p.marker();
|
let marker = p.marker();
|
||||||
p.end_group();
|
p.end_group();
|
||||||
marker.convert(p, NodeKind::Atom(r.into()));
|
marker.convert(p, SyntaxKind::Atom(r.into()));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn math_align(p: &mut Parser) {
|
fn math_align(p: &mut Parser) {
|
||||||
p.perform(NodeKind::Align, |p| {
|
p.perform(SyntaxKind::Align, |p| {
|
||||||
p.assert(NodeKind::Amp);
|
p.assert(SyntaxKind::Amp);
|
||||||
while p.eat_if(NodeKind::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();
|
p.eat();
|
||||||
let prec = op.precedence();
|
let prec = op.precedence();
|
||||||
expr_prec(p, atomic, prec)?;
|
expr_prec(p, atomic, prec)?;
|
||||||
marker.end(p, NodeKind::Unary);
|
marker.end(p, SyntaxKind::Unary);
|
||||||
}
|
}
|
||||||
_ => primary(p, atomic)?,
|
_ => primary(p, atomic)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// Parenthesis or bracket means this is a function call.
|
// Parenthesis or bracket means this is a function call.
|
||||||
if let Some(NodeKind::LeftParen | NodeKind::LeftBracket) = p.peek_direct() {
|
if let Some(SyntaxKind::LeftParen | SyntaxKind::LeftBracket) = p.peek_direct() {
|
||||||
marker.perform(p, NodeKind::FuncCall, args)?;
|
marker.perform(p, SyntaxKind::FuncCall, args)?;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -513,18 +513,19 @@ fn expr_prec(p: &mut Parser, atomic: bool, min_prec: usize) -> ParseResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Method call or field access.
|
// Method call or field access.
|
||||||
if p.eat_if(NodeKind::Dot) {
|
if p.eat_if(SyntaxKind::Dot) {
|
||||||
ident(p)?;
|
ident(p)?;
|
||||||
if let Some(NodeKind::LeftParen | NodeKind::LeftBracket) = p.peek_direct() {
|
if let Some(SyntaxKind::LeftParen | SyntaxKind::LeftBracket) = p.peek_direct()
|
||||||
marker.perform(p, NodeKind::MethodCall, args)?;
|
{
|
||||||
|
marker.perform(p, SyntaxKind::MethodCall, args)?;
|
||||||
} else {
|
} else {
|
||||||
marker.end(p, NodeKind::FieldAccess);
|
marker.end(p, SyntaxKind::FieldAccess);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let op = if p.eat_if(NodeKind::Not) {
|
let op = if p.eat_if(SyntaxKind::Not) {
|
||||||
if p.at(NodeKind::In) {
|
if p.at(SyntaxKind::In) {
|
||||||
BinOp::NotIn
|
BinOp::NotIn
|
||||||
} else {
|
} else {
|
||||||
p.expected("keyword `in`");
|
p.expected("keyword `in`");
|
||||||
@ -549,7 +550,7 @@ fn expr_prec(p: &mut Parser, atomic: bool, min_prec: usize) -> ParseResult {
|
|||||||
Assoc::Right => {}
|
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(())
|
Ok(())
|
||||||
@ -562,39 +563,39 @@ fn primary(p: &mut Parser, atomic: bool) -> ParseResult {
|
|||||||
|
|
||||||
match p.peek() {
|
match p.peek() {
|
||||||
// Things that start with an identifier.
|
// Things that start with an identifier.
|
||||||
Some(NodeKind::Ident(_)) => {
|
Some(SyntaxKind::Ident(_)) => {
|
||||||
let marker = p.marker();
|
let marker = p.marker();
|
||||||
p.eat();
|
p.eat();
|
||||||
|
|
||||||
// Arrow means this is a closure's lone parameter.
|
// Arrow means this is a closure's lone parameter.
|
||||||
if !atomic && p.at(NodeKind::Arrow) {
|
if !atomic && p.at(SyntaxKind::Arrow) {
|
||||||
marker.end(p, NodeKind::Params);
|
marker.end(p, SyntaxKind::Params);
|
||||||
p.assert(NodeKind::Arrow);
|
p.assert(SyntaxKind::Arrow);
|
||||||
marker.perform(p, NodeKind::Closure, expr)
|
marker.perform(p, SyntaxKind::Closure, expr)
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Structures.
|
// Structures.
|
||||||
Some(NodeKind::LeftParen) => parenthesized(p, atomic),
|
Some(SyntaxKind::LeftParen) => parenthesized(p, atomic),
|
||||||
Some(NodeKind::LeftBrace) => Ok(code_block(p)),
|
Some(SyntaxKind::LeftBrace) => Ok(code_block(p)),
|
||||||
Some(NodeKind::LeftBracket) => Ok(content_block(p)),
|
Some(SyntaxKind::LeftBracket) => Ok(content_block(p)),
|
||||||
|
|
||||||
// Keywords.
|
// Keywords.
|
||||||
Some(NodeKind::Let) => let_binding(p),
|
Some(SyntaxKind::Let) => let_binding(p),
|
||||||
Some(NodeKind::Set) => set_rule(p),
|
Some(SyntaxKind::Set) => set_rule(p),
|
||||||
Some(NodeKind::Show) => show_rule(p),
|
Some(SyntaxKind::Show) => show_rule(p),
|
||||||
Some(NodeKind::If) => conditional(p),
|
Some(SyntaxKind::If) => conditional(p),
|
||||||
Some(NodeKind::While) => while_loop(p),
|
Some(SyntaxKind::While) => while_loop(p),
|
||||||
Some(NodeKind::For) => for_loop(p),
|
Some(SyntaxKind::For) => for_loop(p),
|
||||||
Some(NodeKind::Import) => module_import(p),
|
Some(SyntaxKind::Import) => module_import(p),
|
||||||
Some(NodeKind::Include) => module_include(p),
|
Some(SyntaxKind::Include) => module_include(p),
|
||||||
Some(NodeKind::Break) => break_stmt(p),
|
Some(SyntaxKind::Break) => break_stmt(p),
|
||||||
Some(NodeKind::Continue) => continue_stmt(p),
|
Some(SyntaxKind::Continue) => continue_stmt(p),
|
||||||
Some(NodeKind::Return) => return_stmt(p),
|
Some(SyntaxKind::Return) => return_stmt(p),
|
||||||
|
|
||||||
Some(NodeKind::Error(_, _)) => {
|
Some(SyntaxKind::Error(_, _)) => {
|
||||||
p.eat();
|
p.eat();
|
||||||
Err(ParseError)
|
Err(ParseError)
|
||||||
}
|
}
|
||||||
@ -610,13 +611,13 @@ fn primary(p: &mut Parser, atomic: bool) -> ParseResult {
|
|||||||
fn literal(p: &mut Parser) -> bool {
|
fn literal(p: &mut Parser) -> bool {
|
||||||
match p.peek() {
|
match p.peek() {
|
||||||
Some(
|
Some(
|
||||||
NodeKind::None
|
SyntaxKind::None
|
||||||
| NodeKind::Auto
|
| SyntaxKind::Auto
|
||||||
| NodeKind::Int(_)
|
| SyntaxKind::Int(_)
|
||||||
| NodeKind::Float(_)
|
| SyntaxKind::Float(_)
|
||||||
| NodeKind::Bool(_)
|
| SyntaxKind::Bool(_)
|
||||||
| NodeKind::Numeric(_, _)
|
| SyntaxKind::Numeric(_, _)
|
||||||
| NodeKind::Str(_),
|
| SyntaxKind::Str(_),
|
||||||
) => {
|
) => {
|
||||||
p.eat();
|
p.eat();
|
||||||
true
|
true
|
||||||
@ -627,7 +628,7 @@ fn literal(p: &mut Parser) -> bool {
|
|||||||
|
|
||||||
fn ident(p: &mut Parser) -> ParseResult {
|
fn ident(p: &mut Parser) -> ParseResult {
|
||||||
match p.peek() {
|
match p.peek() {
|
||||||
Some(NodeKind::Ident(_)) => {
|
Some(SyntaxKind::Ident(_)) => {
|
||||||
p.eat();
|
p.eat();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -647,7 +648,7 @@ fn parenthesized(p: &mut Parser, atomic: bool) -> ParseResult {
|
|||||||
let marker = p.marker();
|
let marker = p.marker();
|
||||||
|
|
||||||
p.start_group(Group::Paren);
|
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;
|
let kind = collection(p, true).0;
|
||||||
p.end_group();
|
p.end_group();
|
||||||
|
|
||||||
@ -658,15 +659,15 @@ fn parenthesized(p: &mut Parser, atomic: bool) -> ParseResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Arrow means this is a closure's parameter list.
|
// Arrow means this is a closure's parameter list.
|
||||||
if !atomic && p.at(NodeKind::Arrow) {
|
if !atomic && p.at(SyntaxKind::Arrow) {
|
||||||
params(p, marker);
|
params(p, marker);
|
||||||
p.assert(NodeKind::Arrow);
|
p.assert(SyntaxKind::Arrow);
|
||||||
return marker.perform(p, NodeKind::Closure, expr);
|
return marker.perform(p, SyntaxKind::Closure, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transform into the identified collection.
|
// Transform into the identified collection.
|
||||||
match kind {
|
match kind {
|
||||||
CollectionKind::Group => marker.end(p, NodeKind::Parenthesized),
|
CollectionKind::Group => marker.end(p, SyntaxKind::Parenthesized),
|
||||||
CollectionKind::Positional => array(p, marker),
|
CollectionKind::Positional => array(p, marker),
|
||||||
CollectionKind::Named => dict(p, marker),
|
CollectionKind::Named => dict(p, marker),
|
||||||
}
|
}
|
||||||
@ -698,14 +699,14 @@ fn collection(p: &mut Parser, keyed: bool) -> (CollectionKind, usize) {
|
|||||||
|
|
||||||
while !p.eof() {
|
while !p.eof() {
|
||||||
let Ok(item_kind) = item(p, keyed) else {
|
let Ok(item_kind) = item(p, keyed) else {
|
||||||
p.eat_if(NodeKind::Comma);
|
p.eat_if(SyntaxKind::Comma);
|
||||||
collection_kind = Some(CollectionKind::Group);
|
collection_kind = Some(CollectionKind::Group);
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
match item_kind {
|
match item_kind {
|
||||||
NodeKind::Spread => can_group = false,
|
SyntaxKind::Spread => can_group = false,
|
||||||
NodeKind::Named if collection_kind.is_none() => {
|
SyntaxKind::Named if collection_kind.is_none() => {
|
||||||
collection_kind = Some(CollectionKind::Named);
|
collection_kind = Some(CollectionKind::Named);
|
||||||
can_group = false;
|
can_group = false;
|
||||||
}
|
}
|
||||||
@ -725,7 +726,7 @@ fn collection(p: &mut Parser, keyed: bool) -> (CollectionKind, usize) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.eat_if(NodeKind::Comma) {
|
if p.eat_if(SyntaxKind::Comma) {
|
||||||
can_group = false;
|
can_group = false;
|
||||||
} else {
|
} else {
|
||||||
missing_coma = Some(p.trivia_start());
|
missing_coma = Some(p.trivia_start());
|
||||||
@ -741,24 +742,24 @@ fn collection(p: &mut Parser, keyed: bool) -> (CollectionKind, usize) {
|
|||||||
(kind, items)
|
(kind, items)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn item(p: &mut Parser, keyed: bool) -> ParseResult<NodeKind> {
|
fn item(p: &mut Parser, keyed: bool) -> ParseResult<SyntaxKind> {
|
||||||
let marker = p.marker();
|
let marker = p.marker();
|
||||||
if p.eat_if(NodeKind::Dots) {
|
if p.eat_if(SyntaxKind::Dots) {
|
||||||
marker.perform(p, NodeKind::Spread, expr)?;
|
marker.perform(p, SyntaxKind::Spread, expr)?;
|
||||||
return Ok(NodeKind::Spread);
|
return Ok(SyntaxKind::Spread);
|
||||||
}
|
}
|
||||||
|
|
||||||
expr(p)?;
|
expr(p)?;
|
||||||
|
|
||||||
if p.at(NodeKind::Colon) {
|
if p.at(SyntaxKind::Colon) {
|
||||||
match marker.after(p).map(|c| c.kind()) {
|
match marker.after(p).map(|c| c.kind()) {
|
||||||
Some(NodeKind::Ident(_)) => {
|
Some(SyntaxKind::Ident(_)) => {
|
||||||
p.eat();
|
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();
|
p.eat();
|
||||||
marker.perform(p, NodeKind::Keyed, expr)?;
|
marker.perform(p, SyntaxKind::Keyed, expr)?;
|
||||||
}
|
}
|
||||||
kind => {
|
kind => {
|
||||||
let mut msg = EcoString::from("expected identifier");
|
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(", found ");
|
||||||
msg.push_str(kind.name());
|
msg.push_str(kind.name());
|
||||||
}
|
}
|
||||||
let error = NodeKind::Error(ErrorPos::Full, msg);
|
let error = SyntaxKind::Error(ErrorPos::Full, msg);
|
||||||
marker.end(p, error);
|
marker.end(p, error);
|
||||||
p.eat();
|
p.eat();
|
||||||
marker.perform(p, NodeKind::Named, expr).ok();
|
marker.perform(p, SyntaxKind::Named, expr).ok();
|
||||||
return Err(ParseError);
|
return Err(ParseError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(NodeKind::Named)
|
Ok(SyntaxKind::Named)
|
||||||
} else {
|
} else {
|
||||||
Ok(NodeKind::None)
|
Ok(SyntaxKind::None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn array(p: &mut Parser, marker: Marker) {
|
fn array(p: &mut Parser, marker: Marker) {
|
||||||
marker.filter_children(p, |x| match x.kind() {
|
marker.filter_children(p, |x| match x.kind() {
|
||||||
NodeKind::Named | NodeKind::Keyed => Err("expected expression"),
|
SyntaxKind::Named | SyntaxKind::Keyed => Err("expected expression"),
|
||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
});
|
});
|
||||||
marker.end(p, NodeKind::Array);
|
marker.end(p, SyntaxKind::Array);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dict(p: &mut Parser, marker: Marker) {
|
fn dict(p: &mut Parser, marker: Marker) {
|
||||||
let mut used = HashSet::new();
|
let mut used = HashSet::new();
|
||||||
marker.filter_children(p, |x| match x.kind() {
|
marker.filter_children(p, |x| match x.kind() {
|
||||||
kind if kind.is_paren() => Ok(()),
|
kind if kind.is_paren() => Ok(()),
|
||||||
NodeKind::Named | NodeKind::Keyed => {
|
SyntaxKind::Named | SyntaxKind::Keyed => {
|
||||||
if let Some(NodeKind::Ident(key) | NodeKind::Str(key)) =
|
if let Some(SyntaxKind::Ident(key) | SyntaxKind::Str(key)) =
|
||||||
x.children().next().map(|child| child.kind())
|
x.children().next().map(|child| child.kind())
|
||||||
{
|
{
|
||||||
if !used.insert(key.clone()) {
|
if !used.insert(key.clone()) {
|
||||||
@ -805,32 +806,32 @@ fn dict(p: &mut Parser, marker: Marker) {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
NodeKind::Spread | NodeKind::Comma | NodeKind::Colon => Ok(()),
|
SyntaxKind::Spread | SyntaxKind::Comma | SyntaxKind::Colon => Ok(()),
|
||||||
_ => Err("expected named or keyed pair"),
|
_ => Err("expected named or keyed pair"),
|
||||||
});
|
});
|
||||||
marker.end(p, NodeKind::Dict);
|
marker.end(p, SyntaxKind::Dict);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn params(p: &mut Parser, marker: Marker) {
|
fn params(p: &mut Parser, marker: Marker) {
|
||||||
marker.filter_children(p, |x| match x.kind() {
|
marker.filter_children(p, |x| match x.kind() {
|
||||||
kind if kind.is_paren() => Ok(()),
|
kind if kind.is_paren() => Ok(()),
|
||||||
NodeKind::Named | NodeKind::Ident(_) | NodeKind::Comma => Ok(()),
|
SyntaxKind::Named | SyntaxKind::Ident(_) | SyntaxKind::Comma => Ok(()),
|
||||||
NodeKind::Spread
|
SyntaxKind::Spread
|
||||||
if matches!(
|
if matches!(
|
||||||
x.children().last().map(|child| child.kind()),
|
x.children().last().map(|child| child.kind()),
|
||||||
Some(&NodeKind::Ident(_))
|
Some(&SyntaxKind::Ident(_))
|
||||||
) =>
|
) =>
|
||||||
{
|
{
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => Err("expected identifier, named pair or argument sink"),
|
_ => Err("expected identifier, named pair or argument sink"),
|
||||||
});
|
});
|
||||||
marker.end(p, NodeKind::Params);
|
marker.end(p, SyntaxKind::Params);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a code block: `{...}`.
|
/// Parse a code block: `{...}`.
|
||||||
fn code_block(p: &mut Parser) {
|
fn code_block(p: &mut Parser) {
|
||||||
p.perform(NodeKind::CodeBlock, |p| {
|
p.perform(SyntaxKind::CodeBlock, |p| {
|
||||||
p.start_group(Group::Brace);
|
p.start_group(Group::Brace);
|
||||||
code(p);
|
code(p);
|
||||||
p.end_group();
|
p.end_group();
|
||||||
@ -846,12 +847,12 @@ fn code(p: &mut Parser) {
|
|||||||
p.end_group();
|
p.end_group();
|
||||||
|
|
||||||
// Forcefully skip over newlines since the group's contents can't.
|
// 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) {
|
fn content_block(p: &mut Parser) {
|
||||||
p.perform(NodeKind::ContentBlock, |p| {
|
p.perform(SyntaxKind::ContentBlock, |p| {
|
||||||
p.start_group(Group::Bracket);
|
p.start_group(Group::Bracket);
|
||||||
markup(p, true);
|
markup(p, true);
|
||||||
p.end_group();
|
p.end_group();
|
||||||
@ -860,16 +861,16 @@ fn content_block(p: &mut Parser) {
|
|||||||
|
|
||||||
fn args(p: &mut Parser) -> ParseResult {
|
fn args(p: &mut Parser) -> ParseResult {
|
||||||
match p.peek_direct() {
|
match p.peek_direct() {
|
||||||
Some(NodeKind::LeftParen) => {}
|
Some(SyntaxKind::LeftParen) => {}
|
||||||
Some(NodeKind::LeftBracket) => {}
|
Some(SyntaxKind::LeftBracket) => {}
|
||||||
_ => {
|
_ => {
|
||||||
p.expected_found("argument list");
|
p.expected_found("argument list");
|
||||||
return Err(ParseError);
|
return Err(ParseError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p.perform(NodeKind::Args, |p| {
|
p.perform(SyntaxKind::Args, |p| {
|
||||||
if p.at(NodeKind::LeftParen) {
|
if p.at(SyntaxKind::LeftParen) {
|
||||||
let marker = p.marker();
|
let marker = p.marker();
|
||||||
p.start_group(Group::Paren);
|
p.start_group(Group::Paren);
|
||||||
collection(p, false);
|
collection(p, false);
|
||||||
@ -877,8 +878,8 @@ fn args(p: &mut Parser) -> ParseResult {
|
|||||||
|
|
||||||
let mut used = HashSet::new();
|
let mut used = HashSet::new();
|
||||||
marker.filter_children(p, |x| match x.kind() {
|
marker.filter_children(p, |x| match x.kind() {
|
||||||
NodeKind::Named => {
|
SyntaxKind::Named => {
|
||||||
if let Some(NodeKind::Ident(ident)) =
|
if let Some(SyntaxKind::Ident(ident)) =
|
||||||
x.children().next().map(|child| child.kind())
|
x.children().next().map(|child| child.kind())
|
||||||
{
|
{
|
||||||
if !used.insert(ident.clone()) {
|
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);
|
content_block(p);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -900,14 +901,14 @@ fn args(p: &mut Parser) -> ParseResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn let_binding(p: &mut Parser) -> ParseResult {
|
fn let_binding(p: &mut Parser) -> ParseResult {
|
||||||
p.perform(NodeKind::LetBinding, |p| {
|
p.perform(SyntaxKind::LetBinding, |p| {
|
||||||
p.assert(NodeKind::Let);
|
p.assert(SyntaxKind::Let);
|
||||||
|
|
||||||
let marker = p.marker();
|
let marker = p.marker();
|
||||||
ident(p)?;
|
ident(p)?;
|
||||||
|
|
||||||
// If a parenthesis follows, this is a function definition.
|
// 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 {
|
if has_params {
|
||||||
let marker = p.marker();
|
let marker = p.marker();
|
||||||
p.start_group(Group::Paren);
|
p.start_group(Group::Paren);
|
||||||
@ -916,7 +917,7 @@ fn let_binding(p: &mut Parser) -> ParseResult {
|
|||||||
params(p, marker);
|
params(p, marker);
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.eat_if(NodeKind::Eq) {
|
if p.eat_if(SyntaxKind::Eq) {
|
||||||
expr(p)?;
|
expr(p)?;
|
||||||
} else if has_params {
|
} else if has_params {
|
||||||
// Function definitions must have a body.
|
// 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.
|
// Rewrite into a closure expression if it's a function definition.
|
||||||
if has_params {
|
if has_params {
|
||||||
marker.end(p, NodeKind::Closure);
|
marker.end(p, SyntaxKind::Closure);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -933,11 +934,11 @@ fn let_binding(p: &mut Parser) -> ParseResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set_rule(p: &mut Parser) -> ParseResult {
|
fn set_rule(p: &mut Parser) -> ParseResult {
|
||||||
p.perform(NodeKind::SetRule, |p| {
|
p.perform(SyntaxKind::SetRule, |p| {
|
||||||
p.assert(NodeKind::Set);
|
p.assert(SyntaxKind::Set);
|
||||||
ident(p)?;
|
ident(p)?;
|
||||||
args(p)?;
|
args(p)?;
|
||||||
if p.eat_if(NodeKind::If) {
|
if p.eat_if(SyntaxKind::If) {
|
||||||
expr(p)?;
|
expr(p)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -945,10 +946,10 @@ fn set_rule(p: &mut Parser) -> ParseResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn show_rule(p: &mut Parser) -> ParseResult {
|
fn show_rule(p: &mut Parser) -> ParseResult {
|
||||||
p.perform(NodeKind::ShowRule, |p| {
|
p.perform(SyntaxKind::ShowRule, |p| {
|
||||||
p.assert(NodeKind::Show);
|
p.assert(SyntaxKind::Show);
|
||||||
expr(p)?;
|
expr(p)?;
|
||||||
if p.eat_if(NodeKind::Colon) {
|
if p.eat_if(SyntaxKind::Colon) {
|
||||||
expr(p)?;
|
expr(p)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -956,14 +957,14 @@ fn show_rule(p: &mut Parser) -> ParseResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn conditional(p: &mut Parser) -> ParseResult {
|
fn conditional(p: &mut Parser) -> ParseResult {
|
||||||
p.perform(NodeKind::Conditional, |p| {
|
p.perform(SyntaxKind::Conditional, |p| {
|
||||||
p.assert(NodeKind::If);
|
p.assert(SyntaxKind::If);
|
||||||
|
|
||||||
expr(p)?;
|
expr(p)?;
|
||||||
body(p)?;
|
body(p)?;
|
||||||
|
|
||||||
if p.eat_if(NodeKind::Else) {
|
if p.eat_if(SyntaxKind::Else) {
|
||||||
if p.at(NodeKind::If) {
|
if p.at(SyntaxKind::If) {
|
||||||
conditional(p)?;
|
conditional(p)?;
|
||||||
} else {
|
} else {
|
||||||
body(p)?;
|
body(p)?;
|
||||||
@ -975,27 +976,27 @@ fn conditional(p: &mut Parser) -> ParseResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn while_loop(p: &mut Parser) -> ParseResult {
|
fn while_loop(p: &mut Parser) -> ParseResult {
|
||||||
p.perform(NodeKind::WhileLoop, |p| {
|
p.perform(SyntaxKind::WhileLoop, |p| {
|
||||||
p.assert(NodeKind::While);
|
p.assert(SyntaxKind::While);
|
||||||
expr(p)?;
|
expr(p)?;
|
||||||
body(p)
|
body(p)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn for_loop(p: &mut Parser) -> ParseResult {
|
fn for_loop(p: &mut Parser) -> ParseResult {
|
||||||
p.perform(NodeKind::ForLoop, |p| {
|
p.perform(SyntaxKind::ForLoop, |p| {
|
||||||
p.assert(NodeKind::For);
|
p.assert(SyntaxKind::For);
|
||||||
for_pattern(p)?;
|
for_pattern(p)?;
|
||||||
p.expect(NodeKind::In)?;
|
p.expect(SyntaxKind::In)?;
|
||||||
expr(p)?;
|
expr(p)?;
|
||||||
body(p)
|
body(p)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn for_pattern(p: &mut Parser) -> ParseResult {
|
fn for_pattern(p: &mut Parser) -> ParseResult {
|
||||||
p.perform(NodeKind::ForPattern, |p| {
|
p.perform(SyntaxKind::ForPattern, |p| {
|
||||||
ident(p)?;
|
ident(p)?;
|
||||||
if p.eat_if(NodeKind::Comma) {
|
if p.eat_if(SyntaxKind::Comma) {
|
||||||
ident(p)?;
|
ident(p)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -1003,12 +1004,12 @@ fn for_pattern(p: &mut Parser) -> ParseResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn module_import(p: &mut Parser) -> ParseResult {
|
fn module_import(p: &mut Parser) -> ParseResult {
|
||||||
p.perform(NodeKind::ModuleImport, |p| {
|
p.perform(SyntaxKind::ModuleImport, |p| {
|
||||||
p.assert(NodeKind::Import);
|
p.assert(SyntaxKind::Import);
|
||||||
|
|
||||||
if !p.eat_if(NodeKind::Star) {
|
if !p.eat_if(SyntaxKind::Star) {
|
||||||
// This is the list of identifiers scenario.
|
// This is the list of identifiers scenario.
|
||||||
p.perform(NodeKind::ImportItems, |p| {
|
p.perform(SyntaxKind::ImportItems, |p| {
|
||||||
p.start_group(Group::Imports);
|
p.start_group(Group::Imports);
|
||||||
let marker = p.marker();
|
let marker = p.marker();
|
||||||
let items = collection(p, false).1;
|
let items = collection(p, false).1;
|
||||||
@ -1018,42 +1019,42 @@ fn module_import(p: &mut Parser) -> ParseResult {
|
|||||||
p.end_group();
|
p.end_group();
|
||||||
|
|
||||||
marker.filter_children(p, |n| match n.kind() {
|
marker.filter_children(p, |n| match n.kind() {
|
||||||
NodeKind::Ident(_) | NodeKind::Comma => Ok(()),
|
SyntaxKind::Ident(_) | SyntaxKind::Comma => Ok(()),
|
||||||
_ => Err("expected identifier"),
|
_ => Err("expected identifier"),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
p.expect(NodeKind::From)?;
|
p.expect(SyntaxKind::From)?;
|
||||||
expr(p)
|
expr(p)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn module_include(p: &mut Parser) -> ParseResult {
|
fn module_include(p: &mut Parser) -> ParseResult {
|
||||||
p.perform(NodeKind::ModuleInclude, |p| {
|
p.perform(SyntaxKind::ModuleInclude, |p| {
|
||||||
p.assert(NodeKind::Include);
|
p.assert(SyntaxKind::Include);
|
||||||
expr(p)
|
expr(p)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn break_stmt(p: &mut Parser) -> ParseResult {
|
fn break_stmt(p: &mut Parser) -> ParseResult {
|
||||||
p.perform(NodeKind::LoopBreak, |p| {
|
p.perform(SyntaxKind::LoopBreak, |p| {
|
||||||
p.assert(NodeKind::Break);
|
p.assert(SyntaxKind::Break);
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn continue_stmt(p: &mut Parser) -> ParseResult {
|
fn continue_stmt(p: &mut Parser) -> ParseResult {
|
||||||
p.perform(NodeKind::LoopContinue, |p| {
|
p.perform(SyntaxKind::LoopContinue, |p| {
|
||||||
p.assert(NodeKind::Continue);
|
p.assert(SyntaxKind::Continue);
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn return_stmt(p: &mut Parser) -> ParseResult {
|
fn return_stmt(p: &mut Parser) -> ParseResult {
|
||||||
p.perform(NodeKind::FuncReturn, |p| {
|
p.perform(SyntaxKind::FuncReturn, |p| {
|
||||||
p.assert(NodeKind::Return);
|
p.assert(SyntaxKind::Return);
|
||||||
if !p.at(NodeKind::Comma) && !p.eof() {
|
if !p.at(SyntaxKind::Comma) && !p.eof() {
|
||||||
expr(p)?;
|
expr(p)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -1062,8 +1063,8 @@ fn return_stmt(p: &mut Parser) -> ParseResult {
|
|||||||
|
|
||||||
fn body(p: &mut Parser) -> ParseResult {
|
fn body(p: &mut Parser) -> ParseResult {
|
||||||
match p.peek() {
|
match p.peek() {
|
||||||
Some(NodeKind::LeftBracket) => Ok(content_block(p)),
|
Some(SyntaxKind::LeftBracket) => Ok(content_block(p)),
|
||||||
Some(NodeKind::LeftBrace) => Ok(code_block(p)),
|
Some(SyntaxKind::LeftBrace) => Ok(code_block(p)),
|
||||||
_ => {
|
_ => {
|
||||||
p.expected("body");
|
p.expected("body");
|
||||||
Err(ParseError)
|
Err(ParseError)
|
||||||
|
@ -1,9 +1,79 @@
|
|||||||
use std::fmt::{self, Debug, Display, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
use std::num::NonZeroU64;
|
use std::num::NonZeroU64;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use super::SourceId;
|
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.
|
/// A value with a span locating it in the source code.
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct Spanned<T> {
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{SourceId, Span};
|
use super::{SourceId, Span};
|
||||||
|
@ -4,7 +4,7 @@ use unicode_xid::UnicodeXID;
|
|||||||
use unscanny::Scanner;
|
use unscanny::Scanner;
|
||||||
|
|
||||||
use super::resolve::{resolve_hex, resolve_raw, resolve_string};
|
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::geom::{AbsUnit, AngleUnit};
|
||||||
use crate::util::{format_eco, EcoString};
|
use crate::util::{format_eco, EcoString};
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ impl<'s> Tokens<'s> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'s> Iterator for Tokens<'s> {
|
impl<'s> Iterator for Tokens<'s> {
|
||||||
type Item = NodeKind;
|
type Item = SyntaxKind;
|
||||||
|
|
||||||
/// Parse the next token in the source code.
|
/// Parse the next token in the source code.
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -107,9 +107,10 @@ impl<'s> Iterator for Tokens<'s> {
|
|||||||
// Trivia.
|
// Trivia.
|
||||||
'/' if self.s.eat_if('/') => self.line_comment(),
|
'/' if self.s.eat_if('/') => self.line_comment(),
|
||||||
'/' if self.s.eat_if('*') => self.block_comment(),
|
'/' if self.s.eat_if('*') => self.block_comment(),
|
||||||
'*' if self.s.eat_if('/') => {
|
'*' if self.s.eat_if('/') => SyntaxKind::Error(
|
||||||
NodeKind::Error(ErrorPos::Full, "unexpected end of block comment".into())
|
ErrorPos::Full,
|
||||||
}
|
"unexpected end of block comment".into(),
|
||||||
|
),
|
||||||
c if c.is_whitespace() => self.whitespace(c),
|
c if c.is_whitespace() => self.whitespace(c),
|
||||||
|
|
||||||
// Other things.
|
// Other things.
|
||||||
@ -123,15 +124,15 @@ impl<'s> Iterator for Tokens<'s> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'s> Tokens<'s> {
|
impl<'s> Tokens<'s> {
|
||||||
fn line_comment(&mut self) -> NodeKind {
|
fn line_comment(&mut self) -> SyntaxKind {
|
||||||
self.s.eat_until(is_newline);
|
self.s.eat_until(is_newline);
|
||||||
if self.s.peek().is_none() {
|
if self.s.peek().is_none() {
|
||||||
self.terminated = false;
|
self.terminated = false;
|
||||||
}
|
}
|
||||||
NodeKind::LineComment
|
SyntaxKind::LineComment
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_comment(&mut self) -> NodeKind {
|
fn block_comment(&mut self) -> SyntaxKind {
|
||||||
let mut state = '_';
|
let mut state = '_';
|
||||||
let mut depth = 1;
|
let mut depth = 1;
|
||||||
self.terminated = false;
|
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) {
|
if c == ' ' && !self.s.at(char::is_whitespace) {
|
||||||
return NodeKind::Space { newlines: 0 };
|
return SyntaxKind::Space { newlines: 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
self.s.uneat();
|
self.s.uneat();
|
||||||
@ -185,21 +186,21 @@ impl<'s> Tokens<'s> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeKind::Space { newlines }
|
SyntaxKind::Space { newlines }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn markup(&mut self, start: usize, c: char) -> NodeKind {
|
fn markup(&mut self, start: usize, c: char) -> SyntaxKind {
|
||||||
match c {
|
match c {
|
||||||
// Blocks.
|
// Blocks.
|
||||||
'{' => NodeKind::LeftBrace,
|
'{' => SyntaxKind::LeftBrace,
|
||||||
'}' => NodeKind::RightBrace,
|
'}' => SyntaxKind::RightBrace,
|
||||||
'[' => NodeKind::LeftBracket,
|
'[' => SyntaxKind::LeftBracket,
|
||||||
']' => NodeKind::RightBracket,
|
']' => SyntaxKind::RightBracket,
|
||||||
|
|
||||||
// Multi-char things.
|
// Multi-char things.
|
||||||
'#' => self.hash(start),
|
'#' => self.hash(start),
|
||||||
'.' if self.s.eat_if("..") => NodeKind::Shorthand('\u{2026}'),
|
'.' if self.s.eat_if("..") => SyntaxKind::Shorthand('\u{2026}'),
|
||||||
'-' => self.hyph(),
|
'-' => self.hyph(),
|
||||||
'h' if self.s.eat_if("ttp://") || self.s.eat_if("ttps://") => {
|
'h' if self.s.eat_if("ttp://") || self.s.eat_if("ttps://") => {
|
||||||
self.link(start)
|
self.link(start)
|
||||||
@ -213,16 +214,16 @@ impl<'s> Tokens<'s> {
|
|||||||
'\\' => self.backslash(),
|
'\\' => self.backslash(),
|
||||||
|
|
||||||
// Single-char things.
|
// Single-char things.
|
||||||
'~' => NodeKind::Shorthand('\u{00A0}'),
|
'~' => SyntaxKind::Shorthand('\u{00A0}'),
|
||||||
'\'' => NodeKind::SmartQuote { double: false },
|
'\'' => SyntaxKind::SmartQuote { double: false },
|
||||||
'"' => NodeKind::SmartQuote { double: true },
|
'"' => SyntaxKind::SmartQuote { double: true },
|
||||||
'*' if !self.in_word() => NodeKind::Star,
|
'*' if !self.in_word() => SyntaxKind::Star,
|
||||||
'_' if !self.in_word() => NodeKind::Underscore,
|
'_' if !self.in_word() => SyntaxKind::Underscore,
|
||||||
'$' => NodeKind::Dollar,
|
'$' => SyntaxKind::Dollar,
|
||||||
'=' => NodeKind::Eq,
|
'=' => SyntaxKind::Eq,
|
||||||
'+' => NodeKind::Plus,
|
'+' => SyntaxKind::Plus,
|
||||||
'/' => NodeKind::Slash,
|
'/' => SyntaxKind::Slash,
|
||||||
':' => NodeKind::Colon,
|
':' => SyntaxKind::Colon,
|
||||||
|
|
||||||
// Plain text.
|
// Plain text.
|
||||||
_ => self.text(start),
|
_ => self.text(start),
|
||||||
@ -230,7 +231,7 @@ impl<'s> Tokens<'s> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn text(&mut self, start: usize) -> NodeKind {
|
fn text(&mut self, start: usize) -> SyntaxKind {
|
||||||
macro_rules! table {
|
macro_rules! table {
|
||||||
($(|$c:literal)*) => {{
|
($(|$c:literal)*) => {{
|
||||||
let mut t = [false; 128];
|
let mut t = [false; 128];
|
||||||
@ -266,67 +267,67 @@ impl<'s> Tokens<'s> {
|
|||||||
self.s = 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() {
|
match self.s.peek() {
|
||||||
Some('u') if self.s.eat_if("u{") => {
|
Some('u') if self.s.eat_if("u{") => {
|
||||||
let sequence = self.s.eat_while(char::is_ascii_alphanumeric);
|
let sequence = self.s.eat_while(char::is_ascii_alphanumeric);
|
||||||
if self.s.eat_if('}') {
|
if self.s.eat_if('}') {
|
||||||
if let Some(c) = resolve_hex(sequence) {
|
if let Some(c) = resolve_hex(sequence) {
|
||||||
NodeKind::Escape(c)
|
SyntaxKind::Escape(c)
|
||||||
} else {
|
} else {
|
||||||
NodeKind::Error(
|
SyntaxKind::Error(
|
||||||
ErrorPos::Full,
|
ErrorPos::Full,
|
||||||
"invalid unicode escape sequence".into(),
|
"invalid unicode escape sequence".into(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.terminated = false;
|
self.terminated = false;
|
||||||
NodeKind::Error(ErrorPos::End, "expected closing brace".into())
|
SyntaxKind::Error(ErrorPos::End, "expected closing brace".into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Linebreaks.
|
// Linebreaks.
|
||||||
Some(c) if c.is_whitespace() => NodeKind::Linebreak,
|
Some(c) if c.is_whitespace() => SyntaxKind::Linebreak,
|
||||||
None => NodeKind::Linebreak,
|
None => SyntaxKind::Linebreak,
|
||||||
|
|
||||||
// Escapes.
|
// Escapes.
|
||||||
Some(c) => {
|
Some(c) => {
|
||||||
self.s.expect(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) {
|
if self.s.at(is_id_start) {
|
||||||
let read = self.s.eat_while(is_id_continue);
|
let read = self.s.eat_while(is_id_continue);
|
||||||
match keyword(read) {
|
match keyword(read) {
|
||||||
Some(keyword) => keyword,
|
Some(keyword) => keyword,
|
||||||
None => NodeKind::Ident(read.into()),
|
None => SyntaxKind::Ident(read.into()),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.text(start)
|
self.text(start)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hyph(&mut self) -> NodeKind {
|
fn hyph(&mut self) -> SyntaxKind {
|
||||||
if self.s.eat_if('-') {
|
if self.s.eat_if('-') {
|
||||||
if self.s.eat_if('-') {
|
if self.s.eat_if('-') {
|
||||||
NodeKind::Shorthand('\u{2014}')
|
SyntaxKind::Shorthand('\u{2014}')
|
||||||
} else {
|
} else {
|
||||||
NodeKind::Shorthand('\u{2013}')
|
SyntaxKind::Shorthand('\u{2013}')
|
||||||
}
|
}
|
||||||
} else if self.s.eat_if('?') {
|
} else if self.s.eat_if('?') {
|
||||||
NodeKind::Shorthand('\u{00AD}')
|
SyntaxKind::Shorthand('\u{00AD}')
|
||||||
} else {
|
} else {
|
||||||
NodeKind::Minus
|
SyntaxKind::Minus
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn link(&mut self, start: usize) -> NodeKind {
|
fn link(&mut self, start: usize) -> SyntaxKind {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
self.s.eat_while(|c: char| matches!(c,
|
self.s.eat_while(|c: char| matches!(c,
|
||||||
| '0' ..= '9'
|
| '0' ..= '9'
|
||||||
@ -338,10 +339,10 @@ impl<'s> Tokens<'s> {
|
|||||||
if self.s.scout(-1) == Some('.') {
|
if self.s.scout(-1) == Some('.') {
|
||||||
self.s.uneat();
|
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 column = self.column(self.s.cursor() - 1);
|
||||||
|
|
||||||
let mut backticks = 1;
|
let mut backticks = 1;
|
||||||
@ -351,7 +352,7 @@ impl<'s> Tokens<'s> {
|
|||||||
|
|
||||||
// Special case for empty inline block.
|
// Special case for empty inline block.
|
||||||
if backticks == 2 {
|
if backticks == 2 {
|
||||||
return NodeKind::Raw(Arc::new(RawFields {
|
return SyntaxKind::Raw(Arc::new(RawFields {
|
||||||
text: EcoString::new(),
|
text: EcoString::new(),
|
||||||
lang: None,
|
lang: None,
|
||||||
block: false,
|
block: false,
|
||||||
@ -370,7 +371,7 @@ impl<'s> Tokens<'s> {
|
|||||||
|
|
||||||
if found == backticks {
|
if found == backticks {
|
||||||
let end = self.s.cursor() - found as usize;
|
let end = self.s.cursor() - found as usize;
|
||||||
NodeKind::Raw(Arc::new(resolve_raw(
|
SyntaxKind::Raw(Arc::new(resolve_raw(
|
||||||
column,
|
column,
|
||||||
backticks,
|
backticks,
|
||||||
self.s.get(start..end),
|
self.s.get(start..end),
|
||||||
@ -379,7 +380,7 @@ impl<'s> Tokens<'s> {
|
|||||||
self.terminated = false;
|
self.terminated = false;
|
||||||
let remaining = backticks - found;
|
let remaining = backticks - found;
|
||||||
let noun = if remaining == 1 { "backtick" } else { "backticks" };
|
let noun = if remaining == 1 { "backtick" } else { "backticks" };
|
||||||
NodeKind::Error(
|
SyntaxKind::Error(
|
||||||
ErrorPos::End,
|
ErrorPos::End,
|
||||||
if found == 0 {
|
if found == 0 {
|
||||||
format_eco!("expected {} {}", remaining, noun)
|
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);
|
self.s.eat_while(char::is_ascii_digit);
|
||||||
let read = self.s.from(start);
|
let read = self.s.from(start);
|
||||||
if self.s.eat_if('.') {
|
if self.s.eat_if('.') {
|
||||||
if let Ok(number) = read.parse() {
|
if let Ok(number) = read.parse() {
|
||||||
return NodeKind::EnumNumbering(number);
|
return SyntaxKind::EnumNumbering(number);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.text(start)
|
self.text(start)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn label(&mut self) -> NodeKind {
|
fn label(&mut self) -> SyntaxKind {
|
||||||
let label = self.s.eat_while(is_id_continue);
|
let label = self.s.eat_while(is_id_continue);
|
||||||
if self.s.eat_if('>') {
|
if self.s.eat_if('>') {
|
||||||
if !label.is_empty() {
|
if !label.is_empty() {
|
||||||
NodeKind::Label(label.into())
|
SyntaxKind::Label(label.into())
|
||||||
} else {
|
} else {
|
||||||
NodeKind::Error(ErrorPos::Full, "label cannot be empty".into())
|
SyntaxKind::Error(ErrorPos::Full, "label cannot be empty".into())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.terminated = false;
|
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);
|
let label = self.s.eat_while(is_id_continue);
|
||||||
if !label.is_empty() {
|
if !label.is_empty() {
|
||||||
NodeKind::Ref(label.into())
|
SyntaxKind::Ref(label.into())
|
||||||
} else {
|
} else {
|
||||||
self.text(start)
|
self.text(start)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn math(&mut self, start: usize, c: char) -> NodeKind {
|
fn math(&mut self, start: usize, c: char) -> SyntaxKind {
|
||||||
match c {
|
match c {
|
||||||
// Escape sequences.
|
// Escape sequences.
|
||||||
'\\' => self.backslash(),
|
'\\' => self.backslash(),
|
||||||
|
|
||||||
// Single-char things.
|
// Single-char things.
|
||||||
'_' => NodeKind::Underscore,
|
'_' => SyntaxKind::Underscore,
|
||||||
'^' => NodeKind::Hat,
|
'^' => SyntaxKind::Hat,
|
||||||
'/' => NodeKind::Slash,
|
'/' => SyntaxKind::Slash,
|
||||||
'&' => NodeKind::Amp,
|
'&' => SyntaxKind::Amp,
|
||||||
'$' => NodeKind::Dollar,
|
'$' => SyntaxKind::Dollar,
|
||||||
|
|
||||||
// Brackets.
|
// Brackets.
|
||||||
'{' => NodeKind::LeftBrace,
|
'{' => SyntaxKind::LeftBrace,
|
||||||
'}' => NodeKind::RightBrace,
|
'}' => SyntaxKind::RightBrace,
|
||||||
'[' => NodeKind::LeftBracket,
|
'[' => SyntaxKind::LeftBracket,
|
||||||
']' => NodeKind::RightBracket,
|
']' => SyntaxKind::RightBracket,
|
||||||
'(' => NodeKind::LeftParen,
|
'(' => SyntaxKind::LeftParen,
|
||||||
')' => NodeKind::RightParen,
|
')' => SyntaxKind::RightParen,
|
||||||
|
|
||||||
// Identifiers.
|
// Identifiers.
|
||||||
c if is_math_id_start(c) && self.s.at(is_math_id_continue) => {
|
c if is_math_id_start(c) && self.s.at(is_math_id_continue) => {
|
||||||
self.s.eat_while(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.
|
// Numbers.
|
||||||
c if c.is_numeric() => {
|
c if c.is_numeric() => {
|
||||||
self.s.eat_while(char::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.
|
// 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 {
|
match c {
|
||||||
// Blocks.
|
// Blocks.
|
||||||
'{' => NodeKind::LeftBrace,
|
'{' => SyntaxKind::LeftBrace,
|
||||||
'}' => NodeKind::RightBrace,
|
'}' => SyntaxKind::RightBrace,
|
||||||
'[' => NodeKind::LeftBracket,
|
'[' => SyntaxKind::LeftBracket,
|
||||||
']' => NodeKind::RightBracket,
|
']' => SyntaxKind::RightBracket,
|
||||||
|
|
||||||
// Parentheses.
|
// Parentheses.
|
||||||
'(' => NodeKind::LeftParen,
|
'(' => SyntaxKind::LeftParen,
|
||||||
')' => NodeKind::RightParen,
|
')' => SyntaxKind::RightParen,
|
||||||
|
|
||||||
// Two-char operators.
|
// Two-char operators.
|
||||||
'=' if self.s.eat_if('=') => NodeKind::EqEq,
|
'=' if self.s.eat_if('=') => SyntaxKind::EqEq,
|
||||||
'!' if self.s.eat_if('=') => NodeKind::ExclEq,
|
'!' if self.s.eat_if('=') => SyntaxKind::ExclEq,
|
||||||
'<' if self.s.eat_if('=') => NodeKind::LtEq,
|
'<' if self.s.eat_if('=') => SyntaxKind::LtEq,
|
||||||
'>' if self.s.eat_if('=') => NodeKind::GtEq,
|
'>' if self.s.eat_if('=') => SyntaxKind::GtEq,
|
||||||
'+' if self.s.eat_if('=') => NodeKind::PlusEq,
|
'+' if self.s.eat_if('=') => SyntaxKind::PlusEq,
|
||||||
'-' if self.s.eat_if('=') => NodeKind::HyphEq,
|
'-' if self.s.eat_if('=') => SyntaxKind::HyphEq,
|
||||||
'*' if self.s.eat_if('=') => NodeKind::StarEq,
|
'*' if self.s.eat_if('=') => SyntaxKind::StarEq,
|
||||||
'/' if self.s.eat_if('=') => NodeKind::SlashEq,
|
'/' if self.s.eat_if('=') => SyntaxKind::SlashEq,
|
||||||
'.' if self.s.eat_if('.') => NodeKind::Dots,
|
'.' if self.s.eat_if('.') => SyntaxKind::Dots,
|
||||||
'=' if self.s.eat_if('>') => NodeKind::Arrow,
|
'=' if self.s.eat_if('>') => SyntaxKind::Arrow,
|
||||||
|
|
||||||
// Single-char operators.
|
// Single-char operators.
|
||||||
',' => NodeKind::Comma,
|
',' => SyntaxKind::Comma,
|
||||||
';' => NodeKind::Semicolon,
|
';' => SyntaxKind::Semicolon,
|
||||||
':' => NodeKind::Colon,
|
':' => SyntaxKind::Colon,
|
||||||
'+' => NodeKind::Plus,
|
'+' => SyntaxKind::Plus,
|
||||||
'-' => NodeKind::Minus,
|
'-' => SyntaxKind::Minus,
|
||||||
'*' => NodeKind::Star,
|
'*' => SyntaxKind::Star,
|
||||||
'/' => NodeKind::Slash,
|
'/' => SyntaxKind::Slash,
|
||||||
'=' => NodeKind::Eq,
|
'=' => SyntaxKind::Eq,
|
||||||
'<' => NodeKind::Lt,
|
'<' => SyntaxKind::Lt,
|
||||||
'>' => NodeKind::Gt,
|
'>' => SyntaxKind::Gt,
|
||||||
'.' if !self.s.at(char::is_ascii_digit) => NodeKind::Dot,
|
'.' if !self.s.at(char::is_ascii_digit) => SyntaxKind::Dot,
|
||||||
|
|
||||||
// Identifiers.
|
// Identifiers.
|
||||||
c if is_id_start(c) => self.ident(start),
|
c if is_id_start(c) => self.ident(start),
|
||||||
@ -511,22 +512,22 @@ impl<'s> Tokens<'s> {
|
|||||||
'"' => self.string(),
|
'"' => self.string(),
|
||||||
|
|
||||||
// Invalid token.
|
// 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);
|
self.s.eat_while(is_id_continue);
|
||||||
match self.s.from(start) {
|
match self.s.from(start) {
|
||||||
"none" => NodeKind::None,
|
"none" => SyntaxKind::None,
|
||||||
"auto" => NodeKind::Auto,
|
"auto" => SyntaxKind::Auto,
|
||||||
"true" => NodeKind::Bool(true),
|
"true" => SyntaxKind::Bool(true),
|
||||||
"false" => NodeKind::Bool(false),
|
"false" => SyntaxKind::Bool(false),
|
||||||
id => keyword(id).unwrap_or_else(|| NodeKind::Ident(id.into())),
|
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`).
|
// Read the first part (integer or fractional depending on `first`).
|
||||||
self.s.eat_while(char::is_ascii_digit);
|
self.s.eat_while(char::is_ascii_digit);
|
||||||
|
|
||||||
@ -554,30 +555,30 @@ impl<'s> Tokens<'s> {
|
|||||||
// Find out whether it is a simple number.
|
// Find out whether it is a simple number.
|
||||||
if suffix.is_empty() {
|
if suffix.is_empty() {
|
||||||
if let Ok(i) = number.parse::<i64>() {
|
if let Ok(i) = number.parse::<i64>() {
|
||||||
return NodeKind::Int(i);
|
return SyntaxKind::Int(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let Ok(v) = number.parse::<f64>() else {
|
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 {
|
match suffix {
|
||||||
"" => NodeKind::Float(v),
|
"" => SyntaxKind::Float(v),
|
||||||
"pt" => NodeKind::Numeric(v, Unit::Length(AbsUnit::Pt)),
|
"pt" => SyntaxKind::Numeric(v, Unit::Length(AbsUnit::Pt)),
|
||||||
"mm" => NodeKind::Numeric(v, Unit::Length(AbsUnit::Mm)),
|
"mm" => SyntaxKind::Numeric(v, Unit::Length(AbsUnit::Mm)),
|
||||||
"cm" => NodeKind::Numeric(v, Unit::Length(AbsUnit::Cm)),
|
"cm" => SyntaxKind::Numeric(v, Unit::Length(AbsUnit::Cm)),
|
||||||
"in" => NodeKind::Numeric(v, Unit::Length(AbsUnit::In)),
|
"in" => SyntaxKind::Numeric(v, Unit::Length(AbsUnit::In)),
|
||||||
"deg" => NodeKind::Numeric(v, Unit::Angle(AngleUnit::Deg)),
|
"deg" => SyntaxKind::Numeric(v, Unit::Angle(AngleUnit::Deg)),
|
||||||
"rad" => NodeKind::Numeric(v, Unit::Angle(AngleUnit::Rad)),
|
"rad" => SyntaxKind::Numeric(v, Unit::Angle(AngleUnit::Rad)),
|
||||||
"em" => NodeKind::Numeric(v, Unit::Em),
|
"em" => SyntaxKind::Numeric(v, Unit::Em),
|
||||||
"fr" => NodeKind::Numeric(v, Unit::Fr),
|
"fr" => SyntaxKind::Numeric(v, Unit::Fr),
|
||||||
"%" => NodeKind::Numeric(v, Unit::Percent),
|
"%" => SyntaxKind::Numeric(v, Unit::Percent),
|
||||||
_ => NodeKind::Error(ErrorPos::Full, "invalid number suffix".into()),
|
_ => SyntaxKind::Error(ErrorPos::Full, "invalid number suffix".into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn string(&mut self) -> NodeKind {
|
fn string(&mut self) -> SyntaxKind {
|
||||||
let mut escaped = false;
|
let mut escaped = false;
|
||||||
let verbatim = self.s.eat_until(|c| {
|
let verbatim = self.s.eat_until(|c| {
|
||||||
if c == '"' && !escaped {
|
if c == '"' && !escaped {
|
||||||
@ -590,10 +591,10 @@ impl<'s> Tokens<'s> {
|
|||||||
|
|
||||||
let string = resolve_string(verbatim);
|
let string = resolve_string(verbatim);
|
||||||
if self.s.eat_if('"') {
|
if self.s.eat_if('"') {
|
||||||
NodeKind::Str(string)
|
SyntaxKind::Str(string)
|
||||||
} else {
|
} else {
|
||||||
self.terminated = false;
|
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 {
|
Some(match ident {
|
||||||
"not" => NodeKind::Not,
|
"not" => SyntaxKind::Not,
|
||||||
"and" => NodeKind::And,
|
"and" => SyntaxKind::And,
|
||||||
"or" => NodeKind::Or,
|
"or" => SyntaxKind::Or,
|
||||||
"let" => NodeKind::Let,
|
"let" => SyntaxKind::Let,
|
||||||
"set" => NodeKind::Set,
|
"set" => SyntaxKind::Set,
|
||||||
"show" => NodeKind::Show,
|
"show" => SyntaxKind::Show,
|
||||||
"if" => NodeKind::If,
|
"if" => SyntaxKind::If,
|
||||||
"else" => NodeKind::Else,
|
"else" => SyntaxKind::Else,
|
||||||
"for" => NodeKind::For,
|
"for" => SyntaxKind::For,
|
||||||
"in" => NodeKind::In,
|
"in" => SyntaxKind::In,
|
||||||
"while" => NodeKind::While,
|
"while" => SyntaxKind::While,
|
||||||
"break" => NodeKind::Break,
|
"break" => SyntaxKind::Break,
|
||||||
"continue" => NodeKind::Continue,
|
"continue" => SyntaxKind::Continue,
|
||||||
"return" => NodeKind::Return,
|
"return" => SyntaxKind::Return,
|
||||||
"import" => NodeKind::Import,
|
"import" => SyntaxKind::Import,
|
||||||
"include" => NodeKind::Include,
|
"include" => SyntaxKind::Include,
|
||||||
"from" => NodeKind::From,
|
"from" => SyntaxKind::From,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -715,36 +716,36 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use ErrorPos::*;
|
use ErrorPos::*;
|
||||||
use NodeKind::*;
|
|
||||||
use Option::None;
|
use Option::None;
|
||||||
|
use SyntaxKind::*;
|
||||||
use TokenMode::{Code, Markup};
|
use TokenMode::{Code, Markup};
|
||||||
|
|
||||||
fn Space(newlines: usize) -> NodeKind {
|
fn Space(newlines: usize) -> SyntaxKind {
|
||||||
NodeKind::Space { newlines }
|
SyntaxKind::Space { newlines }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Raw(text: &str, lang: Option<&str>, block: bool) -> NodeKind {
|
fn Raw(text: &str, lang: Option<&str>, block: bool) -> SyntaxKind {
|
||||||
NodeKind::Raw(Arc::new(RawFields {
|
SyntaxKind::Raw(Arc::new(RawFields {
|
||||||
text: text.into(),
|
text: text.into(),
|
||||||
lang: lang.map(Into::into),
|
lang: lang.map(Into::into),
|
||||||
block,
|
block,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Str(string: &str) -> NodeKind {
|
fn Str(string: &str) -> SyntaxKind {
|
||||||
NodeKind::Str(string.into())
|
SyntaxKind::Str(string.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Text(string: &str) -> NodeKind {
|
fn Text(string: &str) -> SyntaxKind {
|
||||||
NodeKind::Text(string.into())
|
SyntaxKind::Text(string.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Ident(ident: &str) -> NodeKind {
|
fn Ident(ident: &str) -> SyntaxKind {
|
||||||
NodeKind::Ident(ident.into())
|
SyntaxKind::Ident(ident.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Error(pos: ErrorPos, message: &str) -> NodeKind {
|
fn Error(pos: ErrorPos, message: &str) -> SyntaxKind {
|
||||||
NodeKind::Error(pos, message.into())
|
SyntaxKind::Error(pos, message.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Building blocks for suffix testing.
|
/// Building blocks for suffix testing.
|
||||||
@ -769,7 +770,7 @@ mod tests {
|
|||||||
// - the suffix string
|
// - the suffix string
|
||||||
// - the resulting suffix NodeKind
|
// - the resulting suffix NodeKind
|
||||||
fn suffixes(
|
fn suffixes(
|
||||||
) -> impl Iterator<Item = (char, Option<TokenMode>, &'static str, NodeKind)> {
|
) -> impl Iterator<Item = (char, Option<TokenMode>, &'static str, SyntaxKind)> {
|
||||||
[
|
[
|
||||||
// Whitespace suffixes.
|
// Whitespace suffixes.
|
||||||
(' ', None, " ", Space(0)),
|
(' ', None, " ", Space(0)),
|
||||||
@ -1089,7 +1090,7 @@ mod tests {
|
|||||||
// Combined integers and floats.
|
// Combined integers and floats.
|
||||||
let nums = ints.iter().map(|&(k, v)| (k, v as f64)).chain(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))),
|
("mm", |x| Numeric(x, Unit::Length(AbsUnit::Mm))),
|
||||||
("pt", |x| Numeric(x, Unit::Length(AbsUnit::Pt))),
|
("pt", |x| Numeric(x, Unit::Length(AbsUnit::Pt))),
|
||||||
("cm", |x| Numeric(x, Unit::Length(AbsUnit::Cm))),
|
("cm", |x| Numeric(x, Unit::Length(AbsUnit::Cm))),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user