diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-10-17 16:47:07 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-10-17 17:11:01 +0200 |
| commit | 4fd031a256b2ecfe524859d5599fafb386395572 (patch) | |
| tree | 14787137b5188666a2133525d10ac0b72357551c /src | |
| parent | 54b38c479060ac06213cb311f22b84bccdf88932 (diff) | |
More spans in AST
Diffstat (limited to 'src')
| -rw-r--r-- | src/diag.rs | 13 | ||||
| -rw-r--r-- | src/eval/capture.rs | 32 | ||||
| -rw-r--r-- | src/eval/mod.rs | 371 | ||||
| -rw-r--r-- | src/parse/incremental.rs | 12 | ||||
| -rw-r--r-- | src/parse/mod.rs | 73 | ||||
| -rw-r--r-- | src/parse/parser.rs | 3 | ||||
| -rw-r--r-- | src/parse/resolve.rs | 8 | ||||
| -rw-r--r-- | src/parse/tokens.rs | 179 | ||||
| -rw-r--r-- | src/source.rs | 4 | ||||
| -rw-r--r-- | src/syntax/ast.rs | 823 | ||||
| -rw-r--r-- | src/syntax/highlight.rs | 114 | ||||
| -rw-r--r-- | src/syntax/kind.rs | 335 |
12 files changed, 1110 insertions, 857 deletions
diff --git a/src/diag.rs b/src/diag.rs index ed4d4756..f4725f00 100644 --- a/src/diag.rs +++ b/src/diag.rs @@ -9,7 +9,7 @@ use std::string::FromUtf8Error; use comemo::Tracked; -use crate::syntax::{Span, Spanned}; +use crate::syntax::{ErrorPos, Span, Spanned}; use crate::util::EcoString; use crate::World; @@ -83,17 +83,6 @@ impl SourceError { } } -/// Where in a node an error should be annotated, -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum ErrorPos { - /// Over the full width of the node. - Full, - /// At the start of the node. - Start, - /// At the end of the node. - End, -} - /// A part of an error's [trace](SourceError::trace). #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum Tracepoint { diff --git a/src/eval/capture.rs b/src/eval/capture.rs index b7570fe9..289d31e1 100644 --- a/src/eval/capture.rs +++ b/src/eval/capture.rs @@ -1,6 +1,6 @@ use super::{Scope, Scopes, Value}; -use crate::syntax::ast::{ClosureParam, Expr, Ident, Imports, TypedNode}; -use crate::syntax::SyntaxNode; +use crate::syntax::ast::TypedNode; +use crate::syntax::{ast, SyntaxNode}; /// A visitor that captures variable slots. pub struct CapturesVisitor<'a> { @@ -25,12 +25,12 @@ impl<'a> CapturesVisitor<'a> { } /// Bind a new internal variable. - pub fn bind(&mut self, ident: Ident) { + pub fn bind(&mut self, ident: ast::Ident) { self.internal.top.define(ident.take(), Value::None); } /// Capture a variable if it isn't internal. - pub fn capture(&mut self, ident: Ident) { + pub fn capture(&mut self, ident: ast::Ident) { if self.internal.get(&ident).is_err() { if let Ok(value) = self.external.get(&ident) { self.captures.define_captured(ident.take(), value.clone()); @@ -45,10 +45,10 @@ impl<'a> CapturesVisitor<'a> { // Identifiers that shouldn't count as captures because they // actually bind a new name are handled below (individually through // the expressions that contain them). - Some(Expr::Ident(ident)) => self.capture(ident), + Some(ast::Expr::Ident(ident)) => self.capture(ident), // Code and content blocks create a scope. - Some(Expr::Code(_) | Expr::Content(_)) => { + Some(ast::Expr::Code(_) | ast::Expr::Content(_)) => { self.internal.enter(); for child in node.children() { self.visit(child); @@ -59,18 +59,18 @@ impl<'a> CapturesVisitor<'a> { // A closure contains parameter bindings, which are bound before the // body is evaluated. Care must be taken so that the default values // of named parameters cannot access previous parameter bindings. - Some(Expr::Closure(expr)) => { + Some(ast::Expr::Closure(expr)) => { for param in expr.params() { - if let ClosureParam::Named(named) = param { + if let ast::Param::Named(named) = param { self.visit(named.expr().as_untyped()); } } for param in expr.params() { match param { - ClosureParam::Pos(ident) => self.bind(ident), - ClosureParam::Named(named) => self.bind(named.name()), - ClosureParam::Sink(ident) => self.bind(ident), + ast::Param::Pos(ident) => self.bind(ident), + ast::Param::Named(named) => self.bind(named.name()), + ast::Param::Sink(ident) => self.bind(ident), } } @@ -79,7 +79,7 @@ impl<'a> CapturesVisitor<'a> { // A let expression contains a binding, but that binding is only // active after the body is evaluated. - Some(Expr::Let(expr)) => { + Some(ast::Expr::Let(expr)) => { if let Some(init) = expr.init() { self.visit(init.as_untyped()); } @@ -88,7 +88,7 @@ impl<'a> CapturesVisitor<'a> { // A show rule contains a binding, but that binding is only active // after the target has been evaluated. - Some(Expr::Show(show)) => { + Some(ast::Expr::Show(show)) => { self.visit(show.pattern().as_untyped()); if let Some(binding) = show.binding() { self.bind(binding); @@ -99,7 +99,7 @@ impl<'a> CapturesVisitor<'a> { // A for loop contains one or two bindings in its pattern. These are // active after the iterable is evaluated but before the body is // evaluated. - Some(Expr::For(expr)) => { + Some(ast::Expr::For(expr)) => { self.visit(expr.iter().as_untyped()); let pattern = expr.pattern(); if let Some(key) = pattern.key() { @@ -111,9 +111,9 @@ impl<'a> CapturesVisitor<'a> { // An import contains items, but these are active only after the // path is evaluated. - Some(Expr::Import(expr)) => { + Some(ast::Expr::Import(expr)) => { self.visit(expr.path().as_untyped()); - if let Imports::Items(items) = expr.imports() { + if let ast::Imports::Items(items) = expr.imports() { for item in items { self.bind(item); } diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 26b4130b..0a3d6545 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -43,8 +43,8 @@ use crate::geom::{Angle, Em, Fraction, Length, Ratio}; use crate::library; use crate::model::{Content, Pattern, Recipe, StyleEntry, StyleMap}; use crate::source::SourceId; -use crate::syntax::ast::*; -use crate::syntax::{Span, Spanned}; +use crate::syntax::ast::TypedNode; +use crate::syntax::{ast, Span, Spanned, Unit}; use crate::util::EcoString; use crate::World; @@ -133,25 +133,25 @@ pub trait Eval { fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output>; } -impl Eval for MarkupNode { +impl Eval for ast::Markup { type Output = Content; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { - eval_markup(vm, &mut self.items()) + eval_markup(vm, &mut self.children()) } } /// Evaluate a stream of markup nodes. fn eval_markup( vm: &mut Vm, - nodes: &mut impl Iterator<Item = MarkupItem>, + nodes: &mut impl Iterator<Item = ast::MarkupNode>, ) -> SourceResult<Content> { let flow = vm.flow.take(); let mut seq = Vec::with_capacity(nodes.size_hint().1.unwrap_or_default()); while let Some(node) = nodes.next() { seq.push(match node { - MarkupItem::Expr(Expr::Set(set)) => { + ast::MarkupNode::Expr(ast::Expr::Set(set)) => { let styles = set.eval(vm)?; if vm.flow.is_some() { break; @@ -159,7 +159,7 @@ fn eval_markup( eval_markup(vm, nodes)?.styled_with_map(styles) } - MarkupItem::Expr(Expr::Show(show)) => { + ast::MarkupNode::Expr(ast::Expr::Show(show)) => { let recipe = show.eval(vm)?; if vm.flow.is_some() { break; @@ -168,7 +168,7 @@ fn eval_markup( eval_markup(vm, nodes)? .styled_with_entry(StyleEntry::Recipe(recipe).into()) } - MarkupItem::Expr(Expr::Wrap(wrap)) => { + ast::MarkupNode::Expr(ast::Expr::Wrap(wrap)) => { let tail = eval_markup(vm, nodes)?; vm.scopes.top.define(wrap.binding().take(), tail); wrap.body().eval(vm)?.display() @@ -189,35 +189,86 @@ fn eval_markup( Ok(Content::sequence(seq)) } -impl Eval for MarkupItem { +impl Eval for ast::MarkupNode { type Output = Content; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { - Ok(match self { - Self::Space => Content::Space, - Self::Parbreak => Content::Parbreak, - &Self::Linebreak => Content::Linebreak { justify: false }, - Self::Text(text) => Content::Text(text.clone()), - &Self::Quote { double } => Content::Quote { double }, - Self::Strong(strong) => strong.eval(vm)?, - Self::Emph(emph) => emph.eval(vm)?, - Self::Link(url) => { - Content::show(library::text::LinkNode::from_url(url.clone())) - } - Self::Raw(raw) => raw.eval(vm)?, - Self::Math(math) => math.eval(vm)?, - Self::Heading(heading) => heading.eval(vm)?, - Self::List(list) => list.eval(vm)?, - Self::Enum(enum_) => enum_.eval(vm)?, - Self::Desc(desc) => desc.eval(vm)?, - Self::Label(_) => Content::Empty, - Self::Ref(label) => Content::show(library::structure::RefNode(label.clone())), - Self::Expr(expr) => expr.eval(vm)?.display(), + match self { + Self::Space(v) => v.eval(vm), + Self::Linebreak(v) => v.eval(vm), + Self::Text(v) => v.eval(vm), + Self::Escape(v) => v.eval(vm), + Self::Shorthand(v) => v.eval(vm), + Self::SmartQuote(v) => v.eval(vm), + Self::Strong(v) => v.eval(vm), + Self::Emph(v) => v.eval(vm), + Self::Link(v) => v.eval(vm), + Self::Raw(v) => v.eval(vm), + Self::Math(v) => v.eval(vm), + Self::Heading(v) => v.eval(vm), + Self::List(v) => v.eval(vm), + Self::Enum(v) => v.eval(vm), + Self::Desc(v) => v.eval(vm), + Self::Label(v) => v.eval(vm), + Self::Ref(v) => v.eval(vm), + Self::Expr(v) => v.eval(vm).map(Value::display), + } + } +} + +impl Eval for ast::Space { + type Output = Content; + + fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> { + Ok(if self.newlines() < 2 { + Content::Space + } else { + Content::Parbreak }) } } -impl Eval for StrongNode { +impl Eval for ast::Linebreak { + type Output = Content; + + fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> { + Ok(Content::Linebreak { justify: false }) + } +} + +impl Eval for ast::Text { + type Output = Content; + + fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> { + Ok(Content::Text(self.get().clone())) + } +} + +impl Eval for ast::Escape { + type Output = Content; + + fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> { + Ok(Content::Text(self.get().into())) + } +} + +impl Eval for ast::Shorthand { + type Output = Content; + + fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> { + Ok(Content::Text(self.get().into())) + } +} + +impl Eval for ast::SmartQuote { + type Output = Content; + + fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> { + Ok(Content::Quote { double: self.double() }) + } +} + +impl Eval for ast::Strong { type Output = Content; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -227,7 +278,7 @@ impl Eval for StrongNode { } } -impl Eval for EmphNode { +impl Eval for ast::Emph { type Output = Content; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -237,27 +288,39 @@ impl Eval for EmphNode { } } -impl Eval for RawNode { +impl Eval for ast::Link { + type Output = Content; + + fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> { + Ok(Content::show(library::text::LinkNode::from_url( + self.url().clone(), + ))) + } +} + +impl Eval for ast::Raw { type Output = Content; fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> { let content = Content::show(library::text::RawNode { - text: self.text.clone(), - block: self.block, + text: self.text().clone(), + block: self.block(), }); - Ok(match self.lang { - Some(_) => content.styled(library::text::RawNode::LANG, self.lang.clone()), + Ok(match self.lang() { + Some(_) => content.styled(library::text::RawNode::LANG, self.lang().cloned()), None => content, }) } } -impl Eval for MathNode { +impl Eval for ast::Math { type Output = Content; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { - let nodes = - self.items().map(|node| node.eval(vm)).collect::<SourceResult<_>>()?; + let nodes = self + .children() + .map(|node| node.eval(vm)) + .collect::<SourceResult<_>>()?; Ok(Content::show(library::math::MathNode::Row( Arc::new(nodes), self.span(), @@ -265,20 +328,21 @@ impl Eval for MathNode { } } -impl Eval for MathItem { +impl Eval for ast::MathNode { type Output = library::math::MathNode; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { Ok(match self { - Self::Space => library::math::MathNode::Space, - Self::Linebreak => library::math::MathNode::Linebreak, - Self::Atom(atom) => library::math::MathNode::Atom(atom.clone()), + Self::Space(_) => library::math::MathNode::Space, + Self::Linebreak(_) => library::math::MathNode::Linebreak, + Self::Escape(c) => library::math::MathNode::Atom(c.get().into()), + Self::Atom(atom) => library::math::MathNode::Atom(atom.get().clone()), Self::Script(node) => node.eval(vm)?, Self::Frac(node) => node.eval(vm)?, Self::Align(node) => node.eval(vm)?, Self::Group(node) => library::math::MathNode::Row( Arc::new( - node.items() + node.children() .map(|node| node.eval(vm)) .collect::<SourceResult<_>>()?, ), @@ -292,7 +356,7 @@ impl Eval for MathItem { } } -impl Eval for ScriptNode { +impl Eval for ast::Script { type Output = library::math::MathNode; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -314,7 +378,7 @@ impl Eval for ScriptNode { } } -impl Eval for FracNode { +impl Eval for ast::Frac { type Output = library::math::MathNode; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -327,7 +391,7 @@ impl Eval for FracNode { } } -impl Eval for AlignNode { +impl Eval for ast::Align { type Output = library::math::MathNode; fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> { @@ -335,7 +399,7 @@ impl Eval for AlignNode { } } -impl Eval for HeadingNode { +impl Eval for ast::Heading { type Output = Content; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -346,7 +410,7 @@ impl Eval for HeadingNode { } } -impl Eval for ListItem { +impl Eval for ast::ListItem { type Output = Content; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -355,7 +419,7 @@ impl Eval for ListItem { } } -impl Eval for EnumItem { +impl Eval for ast::EnumItem { type Output = Content; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -367,7 +431,7 @@ impl Eval for EnumItem { } } -impl Eval for DescItem { +impl Eval for ast::DescItem { type Output = Content; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -379,7 +443,25 @@ impl Eval for DescItem { } } -impl Eval for Expr { +impl Eval for ast::Label { + type Output = Content; + + fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> { + Ok(Content::Empty) + } +} + +impl Eval for ast::Ref { + type Output = Content; + + fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> { + Ok(Content::show(library::structure::RefNode( + self.get().clone(), + ))) + } +} + +impl Eval for ast::Expr { type Output = Value; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -397,7 +479,7 @@ impl Eval for Expr { Self::Content(v) => v.eval(vm).map(Value::Content), Self::Array(v) => v.eval(vm).map(Value::Array), Self::Dict(v) => v.eval(vm).map(Value::Dict), - Self::Group(v) => v.eval(vm), + Self::Parenthesized(v) => v.eval(vm), Self::FieldAccess(v) => v.eval(vm), Self::FuncCall(v) => v.eval(vm), Self::MethodCall(v) => v.eval(vm), @@ -408,7 +490,7 @@ impl Eval for Expr { Self::Set(_) => bail!(forbidden("set")), Self::Show(_) => bail!(forbidden("show")), Self::Wrap(_) => bail!(forbidden("wrap")), - Self::If(v) => v.eval(vm), + Self::Conditional(v) => v.eval(vm), Self::While(v) => v.eval(vm), Self::For(v) => v.eval(vm), Self::Import(v) => v.eval(vm), @@ -420,29 +502,29 @@ impl Eval for Expr { } } -impl Eval for Lit { +impl Eval for ast::Lit { type Output = Value; fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> { Ok(match self.kind() { - LitKind::None => Value::None, - LitKind::Auto => Value::Auto, - LitKind::Bool(v) => Value::Bool(v), - LitKind::Int(v) => Value::Int(v), - LitKind::Float(v) => Value::Float(v), - LitKind::Numeric(v, unit) => match unit { + ast::LitKind::None => Value::None, + ast::LitKind::Auto => Value::Auto, + ast::LitKind::Bool(v) => Value::Bool(v), + ast::LitKind::Int(v) => Value::Int(v), + ast::LitKind::Float(v) => Value::Float(v), + ast::LitKind::Numeric(v, unit) => match unit { Unit::Length(unit) => Length::with_unit(v, unit).into(), Unit::Angle(unit) => Angle::with_unit(v, unit).into(), Unit::Em => Em::new(v).into(), Unit::Fr => Fraction::new(v).into(), Unit::Percent => Ratio::new(v / 100.0).into(), }, - LitKind::Str(v) => Value::Str(v.into()), + ast::LitKind::Str(v) => Value::Str(v.into()), }) } } -impl Eval for Ident { +impl Eval for ast::Ident { type Output = Value; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -450,7 +532,7 @@ impl Eval for Ident { } } -impl Eval for CodeBlock { +impl Eval for ast::CodeBlock { type Output = Value; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -462,14 +544,17 @@ impl Eval for CodeBlock { } /// Evaluate a stream of expressions. -fn eval_code(vm: &mut Vm, exprs: &mut impl Iterator<Item = Expr>) -> SourceResult<Value> { +fn eval_code( + vm: &mut Vm, + exprs: &mut impl Iterator<Item = ast::Expr>, +) -> SourceResult<Value> { let flow = vm.flow.take(); let mut output = Value::None; while let Some(expr) = exprs.next() { let span = expr.span(); let value = match expr { - Expr::Set(set) => { + ast::Expr::Set(set) => { let styles = set.eval(vm)?; if vm.flow.is_some() { break; @@ -478,7 +563,7 @@ fn eval_code(vm: &mut Vm, exprs: &mut impl Iterator<Item = Expr>) -> SourceResul let tail = eval_code(vm, exprs)?.display(); Value::Content(tail.styled_with_map(styles)) } - Expr::Show(show) => { + ast::Expr::Show(show) => { let recipe = show.eval(vm)?; let entry = StyleEntry::Recipe(recipe).into(); if vm.flow.is_some() { @@ -488,7 +573,7 @@ fn eval_code(vm: &mut Vm, exprs: &mut impl Iterator<Item = Expr>) -> SourceResul let tail = eval_code(vm, exprs)?.display(); Value::Content(tail.styled_with_entry(entry)) } - Expr::Wrap(wrap) => { + ast::Expr::Wrap(wrap) => { let tail = eval_code(vm, exprs)?; vm.scopes.top.define(wrap.binding().take(), tail); wrap.body().eval(vm)? @@ -511,7 +596,7 @@ fn eval_code(vm: &mut Vm, exprs: &mut impl Iterator<Item = Expr>) -> SourceResul Ok(output) } -impl Eval for ContentBlock { +impl Eval for ast::ContentBlock { type Output = Content; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -522,7 +607,7 @@ impl Eval for ContentBlock { } } -impl Eval for GroupExpr { +impl Eval for ast::Parenthesized { type Output = Value; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -530,7 +615,7 @@ impl Eval for GroupExpr { } } -impl Eval for ArrayExpr { +impl Eval for ast::Array { type Output = Array; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -539,8 +624,8 @@ impl Eval for ArrayExpr { let mut vec = Vec::with_capacity(items.size_hint().0); for item in items { match item { - ArrayItem::Pos(expr) => vec.push(expr.eval(vm)?), - ArrayItem::Spread(expr) => match expr.eval(vm)? { + ast::ArrayItem::Pos(expr) => vec.push(expr.eval(vm)?), + ast::ArrayItem::Spread(expr) => match expr.eval(vm)? { Value::None => {} Value::Array(array) => vec.extend(array.into_iter()), v => bail!(expr.span(), "cannot spread {} into array", v.type_name()), @@ -552,7 +637,7 @@ impl Eval for ArrayExpr { } } -impl Eval for DictExpr { +impl Eval for ast::Dict { type Output = Dict; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -560,13 +645,13 @@ impl Eval for DictExpr { for item in self.items() { match item { - DictItem::Named(named) => { + ast::DictItem::Named(named) => { map.insert(named.name().take().into(), named.expr().eval(vm)?); } - DictItem::Keyed(keyed) => { + ast::DictItem::Keyed(keyed) => { map.insert(keyed.key().into(), keyed.expr().eval(vm)?); } - DictItem::Spread(expr) => match expr.eval(vm)? { + ast::DictItem::Spread(expr) => match expr.eval(vm)? { Value::None => {} Value::Dict(dict) => map.extend(dict.into_iter()), v => bail!( @@ -582,49 +667,49 @@ impl Eval for DictExpr { } } -impl Eval for UnaryExpr { +impl Eval for ast::Unary { type Output = Value; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { let value = self.expr().eval(vm)?; let result = match self.op() { - UnOp::Pos => ops::pos(value), - UnOp::Neg => ops::neg(value), - UnOp::Not => ops::not(value), + ast::UnOp::Pos => ops::pos(value), + ast::UnOp::Neg => ops::neg(value), + ast::UnOp::Not => ops::not(value), }; Ok(result.at(self.span())?) } } -impl Eval for BinaryExpr { +impl Eval for ast::Binary { type Output = Value; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { match self.op() { - BinOp::Add => self.apply(vm, ops::add), - BinOp::Sub => self.apply(vm, ops::sub), - BinOp::Mul => self.apply(vm, ops::mul), - BinOp::Div => self.apply(vm, ops::div), - BinOp::And => self.apply(vm, ops::and), - BinOp::Or => self.apply(vm, ops::or), - BinOp::Eq => self.apply(vm, ops::eq), - BinOp::Neq => self.apply(vm, ops::neq), - BinOp::Lt => self.apply(vm, ops::lt), - BinOp::Leq => self.apply(vm, ops::leq), - BinOp::Gt => self.apply(vm, ops::gt), - BinOp::Geq => self.apply(vm, ops::geq), - BinOp::In => self.apply(vm, ops::in_), - BinOp::NotIn => self.apply(vm, ops::not_in), - BinOp::Assign => self.assign(vm, |_, b| Ok(b)), - BinOp::AddAssign => self.assign(vm, ops::add), - BinOp::SubAssign => self.assign(vm, ops::sub), - BinOp::MulAssign => self.assign(vm, ops::mul), - BinOp::DivAssign => self.assign(vm, ops::div), + ast::BinOp::Add => self.apply(vm, ops::add), + ast::BinOp::Sub => self.apply(vm, ops::sub), + ast::BinOp::Mul => self.apply(vm, ops::mul), + ast::BinOp::Div => self.apply(vm, ops::div), + ast::BinOp::And => self.apply(vm, ops::and), + ast::BinOp::Or => self.apply(vm, ops::or), + ast::BinOp::Eq => self.apply(vm, ops::eq), + ast::BinOp::Neq => self.apply(vm, ops::neq), + ast::BinOp::Lt => self.apply(vm, ops::lt), + ast::BinOp::Leq => self.apply(vm, ops::leq), + ast::BinOp::Gt => self.apply(vm, ops::gt), + ast::BinOp::Geq => self.apply(vm, ops::geq), + ast::BinOp::In => self.apply(vm, ops::in_), + ast::BinOp::NotIn => self.apply(vm, ops::not_in), + ast::BinOp::Assign => self.assign(vm, |_, b| Ok(b)), + ast::BinOp::AddAssign => self.assign(vm, ops::add), + ast::BinOp::SubAssign => self.assign(vm, ops::sub), + ast::BinOp::MulAssign => self.assign(vm, ops::mul), + ast::BinOp::DivAssign => self.assign(vm, ops::div), } } } -impl BinaryExpr { +impl ast::Binary { /// Apply a basic binary operation. fn apply( &self, @@ -634,8 +719,8 @@ impl BinaryExpr { let lhs = self.lhs().eval(vm)?; // Short-circuit boolean operations. - if (self.op() == BinOp::And && lhs == Value::Bool(false)) - || (self.op() == BinOp::Or && lhs == Value::Bool(true)) + if (self.op() == ast::BinOp::And && lhs == Value::Bool(false)) + || (self.op() == ast::BinOp::Or && lhs == Value::Bool(true)) { return Ok(lhs); } @@ -658,11 +743,11 @@ impl BinaryExpr { } } -impl Eval for FieldAccess { +impl Eval for ast::FieldAccess { type Output = Value; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { - let object = self.object().eval(vm)?; + let object = self.target().eval(vm)?; let span = self.field().span(); let field = self.field().take(); @@ -676,7 +761,7 @@ impl Eval for FieldAccess { .clone(), v => bail!( - self.object().span(), + self.target().span(), "cannot access field on {}", v.type_name() ), @@ -684,7 +769,7 @@ impl Eval for FieldAccess { } } -impl Eval for FuncCall { +impl Eval for ast::FuncCall { type Output = Value; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -708,7 +793,7 @@ impl Eval for FuncCall { } } -impl Eval for MethodCall { +impl Eval for ast::MethodCall { type Output = Value; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -718,19 +803,19 @@ impl Eval for MethodCall { Ok(if methods::is_mutating(&method) { let args = self.args().eval(vm)?; - let mut value = self.receiver().access(vm)?; + let mut value = self.target().access(vm)?; methods::call_mut(&mut value, &method, args, span) .trace(vm.world, point, span)?; Value::None } else { - let value = self.receiver().eval(vm)?; + let value = self.target().eval(vm)?; let args = self.args().eval(vm)?; methods::call(vm, value, &method, args, span).trace(vm.world, point, span)? }) } } -impl Eval for CallArgs { +impl Eval for ast::Args { type Output = Args; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -739,21 +824,21 @@ impl Eval for CallArgs { for arg in self.items() { let span = arg.span(); match arg { - CallArg::Pos(expr) => { + ast::Arg::Pos(expr) => { items.push(Arg { span, name: None, value: Spanned::new(expr.eval(vm)?, expr.span()), }); } - CallArg::Named(named) => { + ast::Arg::Named(named) => { items.push(Arg { span, name: Some(named.name().take().into()), value: Spanned::new(named.expr().eval(vm)?, named.expr().span()), }); } - CallArg::Spread(expr) => match expr.eval(vm)? { + ast::Arg::Spread(expr) => match expr.eval(vm)? { Value::None => {} Value::Array(array) => { items.extend(array.into_iter().map(|value| Arg { @@ -779,12 +864,12 @@ impl Eval for CallArgs { } } -impl Eval for ClosureExpr { +impl Eval for ast::Closure { type Output = Value; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { // The closure's name is defined by its let binding if there's one. - let name = self.name().map(Ident::take); + let name = self.name().map(ast::Ident::take); // Collect captured variables. let captured = { @@ -799,13 +884,13 @@ impl Eval for ClosureExpr { // Collect parameters and an optional sink parameter. for param in self.params() { match param { - ClosureParam::Pos(name) => { + ast::Param::Pos(name) => { params.push((name.take(), None)); } - ClosureParam::Named(named) => { + ast::Param::Named(named) => { params.push((named.name().take(), Some(named.expr().eval(vm)?))); } - ClosureParam::Sink(name) => { + ast::Param::Sink(name) => { if sink.is_some() { bail!(name.span(), "only one argument sink is allowed"); } @@ -826,7 +911,7 @@ impl Eval for ClosureExpr { } } -impl Eval for LetExpr { +impl Eval for ast::LetBinding { type Output = Value; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -839,7 +924,7 @@ impl Eval for LetExpr { } } -impl Eval for SetExpr { +impl Eval for ast::SetRule { type Output = StyleMap; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -850,7 +935,7 @@ impl Eval for SetExpr { } } -impl Eval for ShowExpr { +impl Eval for ast::ShowRule { type Output = Recipe; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -887,7 +972,7 @@ impl Eval for ShowExpr { } } -impl Eval for IfExpr { +impl Eval for ast::Conditional { type Output = Value; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -902,7 +987,7 @@ impl Eval for IfExpr { } } -impl Eval for WhileExpr { +impl Eval for ast::WhileLoop { type Output = Value; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -934,7 +1019,7 @@ impl Eval for WhileExpr { } } -impl Eval for ForExpr { +impl Eval for ast::ForLoop { type Output = Value; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -968,7 +1053,7 @@ impl Eval for ForExpr { let iter = self.iter().eval(vm)?; let pattern = self.pattern(); - let key = pattern.key().map(Ident::take); + let key = pattern.key().map(ast::Ident::take); let value = pattern.value().take(); match (key, value, iter) { @@ -1013,7 +1098,7 @@ impl Eval for ForExpr { } } -impl Eval for ImportExpr { +impl Eval for ast::ModuleImport { type Output = Value; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -1022,12 +1107,12 @@ impl Eval for ImportExpr { let module = import(vm, &path, span)?; match self.imports() { - Imports::Wildcard => { + ast::Imports::Wildcard => { for (var, value) in module.scope.iter() { vm.scopes.top.define(var, value.clone()); } } - Imports::Items(idents) => { + ast::Imports::Items(idents) => { for ident in idents { if let Some(value) = module.scope.get(&ident) { vm.scopes.top.define(ident.take(), value.clone()); @@ -1042,7 +1127,7 @@ impl Eval for ImportExpr { } } -impl Eval for IncludeExpr { +impl Eval for ast::ModuleInclude { type Output = Content; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -1071,7 +1156,7 @@ fn import(vm: &mut Vm, path: &str, span: Span) -> SourceResult<Module> { Ok(module) } -impl Eval for BreakExpr { +impl Eval for ast::BreakStmt { type Output = Value; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -1082,7 +1167,7 @@ impl Eval for BreakExpr { } } -impl Eval for ContinueExpr { +impl Eval for ast::ContinueStmt { type Output = Value; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -1093,7 +1178,7 @@ impl Eval for ContinueExpr { } } -impl Eval for ReturnExpr { +impl Eval for ast::ReturnStmt { type Output = Value; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { @@ -1111,29 +1196,29 @@ pub trait Access { fn access<'a>(&self, vm: &'a mut Vm) -> SourceResult<&'a mut Value>; } -impl Access for Expr { +impl Access for ast::Expr { fn access<'a>(&self, vm: &'a mut Vm) -> SourceResult<&'a mut Value> { match self { - Expr::Ident(v) => v.access(vm), - Expr::FieldAccess(v) => v.access(vm), - Expr::FuncCall(v) => v.access(vm), + Self::Ident(v) => v.access(vm), + Self::FieldAccess(v) => v.access(vm), + Self::FuncCall(v) => v.access(vm), _ => bail!(self.span(), "cannot mutate a temporary value"), } } } -impl Access for Ident { +impl Access for ast::Ident { fn access<'a>(&self, vm: &'a mut Vm) -> SourceResult<&'a mut Value> { vm.scopes.get_mut(self).at(self.span()) } } -impl Access for FieldAccess { +impl Access for ast::FieldAccess { fn access<'a>(&self, vm: &'a mut Vm) -> SourceResult<&'a mut Value> { - Ok(match self.object().access(vm)? { + Ok(match self.target().access(vm)? { Value::Dict(dict) => dict.get_mut(self.field().take().into()), v => bail!( - self.object().span(), + self.target().span(), "expected dictionary, found {}", v.type_name(), ), @@ -1141,7 +1226,7 @@ impl Access for FieldAccess { } } -impl Access for FuncCall { +impl Access for ast::FuncCall { fn access<'a>(&self, vm: &'a mut Vm) -> SourceResult<&'a mut Value> { let args = self.args().eval(vm)?; Ok(match self.callee().access(vm)? { diff --git a/src/parse/incremental.rs b/src/parse/incremental.rs index e0be9b6d..4651a784 100644 --- a/src/parse/incremental.rs +++ b/src/parse/incremental.rs @@ -389,16 +389,12 @@ fn is_bounded(kind: &NodeKind) -> bool { match kind { NodeKind::CodeBlock | NodeKind::ContentBlock - | NodeKind::Backslash - | NodeKind::Tilde - | NodeKind::HyphQuest - | NodeKind::Hyph2 - | NodeKind::Hyph3 - | NodeKind::Dot3 - | NodeKind::Quote { .. } + | NodeKind::Linebreak + | NodeKind::SmartQuote { .. } | NodeKind::BlockComment | NodeKind::Space { .. } - | NodeKind::Escape(_) => true, + | NodeKind::Escape(_) + | NodeKind::Shorthand(_) => true, _ => false, } } diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 4f42442f..ac8ec6eb 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -11,9 +11,8 @@ pub use tokens::*; use std::collections::HashSet; -use crate::diag::ErrorPos; use crate::syntax::ast::{Assoc, BinOp, UnOp}; -use crate::syntax::{NodeKind, SyntaxNode}; +use crate::syntax::{ErrorPos, NodeKind, SyntaxNode}; use crate::util::EcoString; /// Parse a source file. @@ -240,14 +239,10 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) { // Text and markup. NodeKind::Text(_) - | NodeKind::Backslash - | NodeKind::Tilde - | NodeKind::HyphQuest - | NodeKind::Hyph2 - | NodeKind::Hyph3 - | NodeKind::Dot3 - | NodeKind::Quote { .. } + | NodeKind::Linebreak + | NodeKind::SmartQuote { .. } | NodeKind::Escape(_) + | NodeKind::Shorthand(_) | NodeKind::Link(_) | NodeKind::Raw(_) | NodeKind::Label(_) @@ -475,15 +470,15 @@ fn math_primary(p: &mut Parser) { match token { // Spaces, atoms and expressions. NodeKind::Space { .. } - | NodeKind::Backslash + | NodeKind::Linebreak | NodeKind::Escape(_) | NodeKind::Atom(_) | NodeKind::Ident(_) => p.eat(), // Groups. - NodeKind::LeftParen => group(p, Group::Paren), - NodeKind::LeftBracket => group(p, Group::Bracket), - NodeKind::LeftBrace => group(p, Group::Brace), + NodeKind::LeftParen => group(p, Group::Paren, '(', ')'), + NodeKind::LeftBracket => group(p, Group::Bracket, '[', ']'), + NodeKind::LeftBrace => group(p, Group::Brace, '{', '}'), // Alignment indactor. NodeKind::Amp => align(p), @@ -493,13 +488,17 @@ fn math_primary(p: &mut Parser) { } /// Parse grouped math. -fn group(p: &mut Parser, group: Group) { +fn group(p: &mut Parser, group: Group, l: char, r: char) { p.perform(NodeKind::Math, |p| { + let marker = p.marker(); p.start_group(group); + marker.convert(p, NodeKind::Atom(l.into())); while !p.eof() { math_node(p); } + let marker = p.marker(); p.end_group(); + marker.convert(p, NodeKind::Atom(r.into())); }) } @@ -532,7 +531,7 @@ fn expr_prec(p: &mut Parser, atomic: bool, min_prec: usize) -> ParseResult { p.eat(); let prec = op.precedence(); expr_prec(p, atomic, prec)?; - marker.end(p, NodeKind::UnaryExpr); + marker.end(p, NodeKind::Unary); } _ => primary(p, atomic)?, }; @@ -585,7 +584,7 @@ fn expr_prec(p: &mut Parser, atomic: bool, min_prec: usize) -> ParseResult { Assoc::Right => {} } - marker.perform(p, NodeKind::BinaryExpr, |p| expr_prec(p, atomic, prec))?; + marker.perform(p, NodeKind::Binary, |p| expr_prec(p, atomic, prec))?; } Ok(()) @@ -605,9 +604,9 @@ fn primary(p: &mut Parser, atomic: bool) -> ParseResult { // Arrow means this is a closure's lone parameter. if !atomic && p.at(NodeKind::Arrow) { - marker.end(p, NodeKind::ClosureParams); + marker.end(p, NodeKind::Params); p.assert(NodeKind::Arrow); - marker.perform(p, NodeKind::ClosureExpr, expr) + marker.perform(p, NodeKind::Closure, expr) } else { Ok(()) } @@ -703,12 +702,12 @@ fn parenthesized(p: &mut Parser, atomic: bool) -> ParseResult { if !atomic && p.at(NodeKind::Arrow) { params(p, marker); p.assert(NodeKind::Arrow); - return marker.perform(p, NodeKind::ClosureExpr, expr); + return marker.perform(p, NodeKind::Closure, expr); } // Transform into the identified collection. match kind { - CollectionKind::Group => marker.end(p, NodeKind::GroupExpr), + CollectionKind::Group => marker.end(p, NodeKind::Parenthesized), CollectionKind::Positional => array(p, marker), CollectionKind::Named => dict(p, marker), } @@ -833,7 +832,7 @@ fn array(p: &mut Parser, marker: Marker) { NodeKind::Named | NodeKind::Keyed => Err("expected expression"), _ => Ok(()), }); - marker.end(p, NodeKind::ArrayExpr); + marker.end(p, NodeKind::Array); } /// Convert a collection into a dictionary, producing errors for anything other @@ -855,7 +854,7 @@ fn dict(p: &mut Parser, marker: Marker) { NodeKind::Spread | NodeKind::Comma | NodeKind::Colon => Ok(()), _ => Err("expected named or keyed pair"), }); - marker.end(p, NodeKind::DictExpr); + marker.end(p, NodeKind::Dict); } /// Convert a collection into a list of parameters, producing errors for @@ -874,7 +873,7 @@ fn params(p: &mut Parser, marker: Marker) { } _ => Err("expected identifier, named pair or argument sink"), }); - marker.end(p, NodeKind::ClosureParams); + marker.end(p, NodeKind::Params); } /// Parse a code block: `{...}`. @@ -920,7 +919,7 @@ fn args(p: &mut Parser) -> ParseResult { } } - p.perform(NodeKind::CallArgs, |p| { + p.perform(NodeKind::Args, |p| { if p.at(NodeKind::LeftParen) { let marker = p.marker(); p.start_group(Group::Paren); @@ -953,7 +952,7 @@ fn args(p: &mut Parser) -> ParseResult { /// Parse a let expression. fn let_expr(p: &mut Parser) -> ParseResult { - p.perform(NodeKind::LetExpr, |p| { + p.perform(NodeKind::LetBinding, |p| { p.assert(NodeKind::Let); let marker = p.marker(); @@ -978,7 +977,7 @@ fn let_expr(p: &mut Parser) -> ParseResult { // Rewrite into a closure expression if it's a function definition. if has_params { - marker.end(p, NodeKind::ClosureExpr); + marker.end(p, NodeKind::Closure); } Ok(()) @@ -987,7 +986,7 @@ fn let_expr(p: &mut Parser) -> ParseResult { /// Parse a set expression. fn set_expr(p: &mut Parser) -> ParseResult { - p.perform(NodeKind::SetExpr, |p| { + p.perform(NodeKind::SetRule, |p| { p.assert(NodeKind::Set); ident(p)?; args(p) @@ -996,7 +995,7 @@ fn set_expr(p: &mut Parser) -> ParseResult { /// Parse a show expression. fn show_expr(p: &mut Parser) -> ParseResult { - p.perform(NodeKind::ShowExpr, |p| { + p.perform(NodeKind::ShowRule, |p| { p.assert(NodeKind::Show); let marker = p.marker(); expr(p)?; @@ -1014,7 +1013,7 @@ fn show_expr(p: &mut Parser) -> ParseResult { /// Parse a wrap expression. fn wrap_expr(p: &mut Parser) -> ParseResult { - p.perform(NodeKind::WrapExpr, |p| { + p.perform(NodeKind::WrapRule, |p| { p.assert(NodeKind::Wrap); ident(p)?; p.expect(NodeKind::In)?; @@ -1024,7 +1023,7 @@ fn wrap_expr(p: &mut Parser) -> ParseResult { /// Parse an if-else expresion. fn if_expr(p: &mut Parser) -> ParseResult { - p.perform(NodeKind::IfExpr, |p| { + p.perform(NodeKind::Conditional, |p| { p.assert(NodeKind::If); expr(p)?; @@ -1044,7 +1043,7 @@ fn if_expr(p: &mut Parser) -> ParseResult { /// Parse a while expresion. fn while_expr(p: &mut Parser) -> ParseResult { - p.perform(NodeKind::WhileExpr, |p| { + p.perform(NodeKind::WhileLoop, |p| { p.assert(NodeKind::While); expr(p)?; body(p) @@ -1053,7 +1052,7 @@ fn while_expr(p: &mut Parser) -> ParseResult { /// Parse a for-in expression. fn for_expr(p: &mut Parser) -> ParseResult { - p.perform(NodeKind::ForExpr, |p| { + p.perform(NodeKind::ForLoop, |p| { p.assert(NodeKind::For); for_pattern(p)?; p.expect(NodeKind::In)?; @@ -1075,7 +1074,7 @@ fn for_pattern(p: &mut Parser) -> ParseResult { /// Parse an import expression. fn import_expr(p: &mut Parser) -> ParseResult { - p.perform(NodeKind::ImportExpr, |p| { + p.perform(NodeKind::ModuleImport, |p| { p.assert(NodeKind::Import); if !p.eat_if(NodeKind::Star) { @@ -1103,7 +1102,7 @@ fn import_expr(p: &mut Parser) -> ParseResult { /// Parse an include expression. fn include_expr(p: &mut Parser) -> ParseResult { - p.perform(NodeKind::IncludeExpr, |p| { + p.perform(NodeKind::ModuleInclude, |p| { p.assert(NodeKind::Include); expr(p) }) @@ -1111,7 +1110,7 @@ fn include_expr(p: &mut Parser) -> ParseResult { /// Parse a break expression. fn break_expr(p: &mut Parser) -> ParseResult { - p.perform(NodeKind::BreakExpr, |p| { + p.perform(NodeKind::BreakStmt, |p| { p.assert(NodeKind::Break); Ok(()) }) @@ -1119,7 +1118,7 @@ fn break_expr(p: &mut Parser) -> ParseResult { /// Parse a continue expression. fn continue_expr(p: &mut Parser) -> ParseResult { - p.perform(NodeKind::ContinueExpr, |p| { + p.perform(NodeKind::ContinueStmt, |p| { p.assert(NodeKind::Continue); Ok(()) }) @@ -1127,7 +1126,7 @@ fn continue_expr(p: &mut Parser) -> ParseResult { /// Parse a return expression. fn return_expr(p: &mut Parser) -> ParseResult { - p.perform(NodeKind::ReturnExpr, |p| { + p.perform(NodeKind::ReturnStmt, |p| { p.assert(NodeKind::Return); if !p.at(NodeKind::Comma) && !p.eof() { expr(p)?; diff --git a/src/parse/parser.rs b/src/parse/parser.rs index fe04f29e..3dbb7d50 100644 --- a/src/parse/parser.rs +++ b/src/parse/parser.rs @@ -3,8 +3,7 @@ use std::mem; use std::ops::Range; use super::{TokenMode, Tokens}; -use crate::diag::ErrorPos; -use crate::syntax::{InnerNode, NodeData, NodeKind, SyntaxNode}; +use crate::syntax::{ErrorPos, InnerNode, NodeData, NodeKind, SyntaxNode}; use crate::util::EcoString; /// A convenient token-based parser. diff --git a/src/parse/resolve.rs b/src/parse/resolve.rs index d68282c0..9fde0cf4 100644 --- a/src/parse/resolve.rs +++ b/src/parse/resolve.rs @@ -1,7 +1,7 @@ use unscanny::Scanner; use super::{is_ident, is_newline}; -use crate::syntax::ast::RawNode; +use crate::syntax::RawKind; use crate::util::EcoString; /// Resolve all escape sequences in a string. @@ -46,17 +46,17 @@ pub fn resolve_hex(sequence: &str) -> Option<char> { } /// Resolve the language tag and trim the raw text. -pub fn resolve_raw(column: usize, backticks: usize, text: &str) -> RawNode { +pub fn resolve_raw(column: usize, backticks: usize, text: &str) -> RawKind { if backticks > 1 { let (tag, inner) = split_at_lang_tag(text); let (text, block) = trim_and_split_raw(column, inner); - RawNode { + RawKind { lang: is_ident(tag).then(|| tag.into()), text: text.into(), block, } } else { - RawNode { + RawKind { lang: None, text: split_lines(text).join("\n").into(), block: false, diff --git a/src/parse/tokens.rs b/src/parse/tokens.rs index 7cba1823..73c64d1e 100644 --- a/src/parse/tokens.rs +++ b/src/parse/tokens.rs @@ -4,10 +4,8 @@ use unicode_xid::UnicodeXID; use unscanny::Scanner; use super::resolve::{resolve_hex, resolve_raw, resolve_string}; -use crate::diag::ErrorPos; use crate::geom::{AngleUnit, LengthUnit}; -use crate::syntax::ast::{RawNode, Unit}; -use crate::syntax::NodeKind; +use crate::syntax::{ErrorPos, NodeKind, RawKind, Unit}; use crate::util::EcoString; /// An iterator over the tokens of a string of source code. @@ -199,14 +197,25 @@ impl<'s> Tokens<'s> { '[' => NodeKind::LeftBracket, ']' => NodeKind::RightBracket, + // Multi-char things. + '#' => self.hash(start), + '.' if self.s.eat_if("..") => NodeKind::Shorthand('\u{2026}'), + '-' => self.hyph(), + 'h' if self.s.eat_if("ttp://") || self.s.eat_if("ttps://") => { + self.link(start) + } + '`' => self.raw(), + c if c.is_ascii_digit() => self.numbering(start), + '<' => self.label(), + '@' => self.reference(start), + // Escape sequences. '\\' => self.backslash(), // Single-char things. - '~' => NodeKind::Tilde, - '.' if self.s.eat_if("..") => NodeKind::Dot3, - '\'' => NodeKind::Quote { double: false }, - '"' => NodeKind::Quote { double: true }, + '~' => NodeKind::Shorthand('\u{00A0}'), + '\'' => NodeKind::SmartQuote { double: false }, + '"' => NodeKind::SmartQuote { double: true }, '*' if !self.in_word() => NodeKind::Star, '_' if !self.in_word() => NodeKind::Underscore, '$' => NodeKind::Dollar, @@ -215,17 +224,6 @@ impl<'s> Tokens<'s> { '/' => NodeKind::Slash, ':' => NodeKind::Colon, - // Multi-char things. - '#' => self.hash(start), - '-' => self.hyph(), - 'h' if self.s.eat_if("ttp://") || self.s.eat_if("ttps://") => { - self.link(start) - } - '`' => self.raw(), - c if c.is_ascii_digit() => self.numbering(start), - '<' => self.label(), - '@' => self.reference(start), - // Plain text. _ => self.text(start), } @@ -291,8 +289,8 @@ impl<'s> Tokens<'s> { } // Linebreaks. - Some(c) if c.is_whitespace() => NodeKind::Backslash, - None => NodeKind::Backslash, + Some(c) if c.is_whitespace() => NodeKind::Linebreak, + None => NodeKind::Linebreak, // Escapes. Some(c) => { @@ -317,24 +315,17 @@ impl<'s> Tokens<'s> { fn hyph(&mut self) -> NodeKind { if self.s.eat_if('-') { if self.s.eat_if('-') { - NodeKind::Hyph3 + NodeKind::Shorthand('\u{2014}') } else { - NodeKind::Hyph2 + NodeKind::Shorthand('\u{2013}') } } else if self.s.eat_if('?') { - NodeKind::HyphQuest + NodeKind::Shorthand('\u{00AD}') } else { NodeKind::Minus } } - fn in_word(&self) -> bool { - let alphanumeric = |c: Option<char>| c.map_or(false, |c| c.is_alphanumeric()); - let prev = self.s.scout(-2); - let next = self.s.peek(); - alphanumeric(prev) && alphanumeric(next) - } - fn link(&mut self, start: usize) -> NodeKind { #[rustfmt::skip] self.s.eat_while(|c: char| matches!(c, @@ -360,7 +351,7 @@ impl<'s> Tokens<'s> { // Special case for empty inline block. if backticks == 2 { - return NodeKind::Raw(Arc::new(RawNode { + return NodeKind::Raw(Arc::new(RawKind { text: EcoString::new(), lang: None, block: false, @@ -567,22 +558,23 @@ impl<'s> Tokens<'s> { } } - if let Ok(f) = number.parse::<f64>() { - match suffix { - "" => NodeKind::Float(f), - "pt" => NodeKind::Numeric(f, Unit::Length(LengthUnit::Pt)), - "mm" => NodeKind::Numeric(f, Unit::Length(LengthUnit::Mm)), - "cm" => NodeKind::Numeric(f, Unit::Length(LengthUnit::Cm)), - "in" => NodeKind::Numeric(f, Unit::Length(LengthUnit::In)), - "deg" => NodeKind::Numeric(f, Unit::Angle(AngleUnit::Deg)), - "rad" => NodeKind::Numeric(f, Unit::Angle(AngleUnit::Rad)), - "em" => NodeKind::Numeric(f, Unit::Em), - "fr" => NodeKind::Numeric(f, Unit::Fr), - "%" => NodeKind::Numeric(f, Unit::Percent), - _ => NodeKind::Error(ErrorPos::Full, "invalid number suffix".into()), - } - } else { - NodeKind::Error(ErrorPos::Full, "invalid number".into()) + let v = match number.parse::<f64>() { + Ok(v) => v, + Err(_) => return NodeKind::Error(ErrorPos::Full, "invalid number".into()), + }; + + match suffix { + "" => NodeKind::Float(v), + "pt" => NodeKind::Numeric(v, Unit::Length(LengthUnit::Pt)), + "mm" => NodeKind::Numeric(v, Unit::Length(LengthUnit::Mm)), + "cm" => NodeKind::Numeric(v, Unit::Length(LengthUnit::Cm)), + "in" => NodeKind::Numeric(v, Unit::Length(LengthUnit::In)), + "deg" => NodeKind::Numeric(v, Unit::Angle(AngleUnit::Deg)), + "rad" => NodeKind::Numeric(v, Unit::Angle(AngleUnit::Rad)), + "em" => NodeKind::Numeric(v, Unit::Em), + "fr" => NodeKind::Numeric(v, Unit::Fr), + "%" => NodeKind::Numeric(v, Unit::Percent), + _ => NodeKind::Error(ErrorPos::Full, "invalid number suffix".into()), } } @@ -605,6 +597,13 @@ impl<'s> Tokens<'s> { NodeKind::Error(ErrorPos::End, "expected quote".into()) } } + + fn in_word(&self) -> bool { + let alphanumeric = |c: Option<char>| c.map_or(false, |c| c.is_alphanumeric()); + let prev = self.s.scout(-2); + let next = self.s.peek(); + alphanumeric(prev) && alphanumeric(next) + } } fn keyword(ident: &str) -> Option<NodeKind> { @@ -724,7 +723,7 @@ mod tests { } fn Raw(text: &str, lang: Option<&str>, block: bool) -> NodeKind { - NodeKind::Raw(Arc::new(RawNode { + NodeKind::Raw(Arc::new(RawKind { text: text.into(), lang: lang.map(Into::into), block, @@ -762,6 +761,43 @@ mod tests { /// - '/': symbols const BLOCKS: &str = " a1/"; + // Suffixes described by four-tuples of: + // + // - block the suffix is part of + // - mode in which the suffix is applicable + // - the suffix string + // - the resulting suffix NodeKind + fn suffixes() + -> impl Iterator<Item = (char, Option<TokenMode>, &'static str, NodeKind)> { + [ + // Whitespace suffixes. + (' ', None, " ", Space(0)), + (' ', None, "\n", Space(1)), + (' ', None, "\r", Space(1)), + (' ', None, "\r\n", Space(1)), + // Letter suffixes. + ('a', Some(Markup), "hello", Text("hello")), + ('a', Some(Markup), "💚", Text("💚")), + ('a', Some(Code), "val", Ident("val")), + ('a', Some(Code), "α", Ident("α")), + ('a', Some(Code), "_", Ident("_")), + // Number suffixes. + ('1', Some(Code), "2", Int(2)), + ('1', Some(Code), ".2", Float(0.2)), + // Symbol suffixes. + ('/', None, "[", LeftBracket), + ('/', None, "//", LineComment), + ('/', None, "/**/", BlockComment), + ('/', Some(Markup), "*", Star), + ('/', Some(Markup), r"\\", Escape('\\')), + ('/', Some(Markup), "#let", Let), + ('/', Some(Code), "(", LeftParen), + ('/', Some(Code), ":", Colon), + ('/', Some(Code), "+=", PlusEq), + ] + .into_iter() + } + macro_rules! t { (Both $($tts:tt)*) => { t!(Markup $($tts)*); @@ -771,41 +807,8 @@ mod tests { // Test without suffix. t!(@$mode: $text => $($token),*); - // Suffixes described by four-tuples of: - // - // - block the suffix is part of - // - mode in which the suffix is applicable - // - the suffix string - // - the resulting suffix NodeKind - let suffixes: &[(char, Option<TokenMode>, &str, NodeKind)] = &[ - // Whitespace suffixes. - (' ', None, " ", Space(0)), - (' ', None, "\n", Space(1)), - (' ', None, "\r", Space(1)), - (' ', None, "\r\n", Space(1)), - // Letter suffixes. - ('a', Some(Markup), "hello", Text("hello")), - ('a', Some(Markup), "💚", Text("💚")), - ('a', Some(Code), "val", Ident("val")), - ('a', Some(Code), "α", Ident("α")), - ('a', Some(Code), "_", Ident("_")), - // Number suffixes. - ('1', Some(Code), "2", Int(2)), - ('1', Some(Code), ".2", Float(0.2)), - // Symbol suffixes. - ('/', None, "[", LeftBracket), - ('/', None, "//", LineComment), - ('/', None, "/**/", BlockComment), - ('/', Some(Markup), "*", Star), - ('/', Some(Markup), r"\\", Escape('\\')), - ('/', Some(Markup), "#let", Let), - ('/', Some(Code), "(", LeftParen), - ('/', Some(Code), ":", Colon), - ('/', Some(Code), "+=", PlusEq), - ]; - // Test with each applicable suffix. - for &(block, mode, suffix, ref token) in suffixes { + for (block, mode, suffix, ref token) in suffixes() { let text = $text; #[allow(unused_variables)] let blocks = BLOCKS; @@ -872,14 +875,14 @@ mod tests { t!(Markup[" /"]: "reha-world" => Text("reha-world")); // Test code symbols in text. - t!(Markup[" /"]: "a():\"b" => Text("a()"), Colon, Quote { double: true }, Text("b")); + t!(Markup[" /"]: "a():\"b" => Text("a()"), Colon, SmartQuote { double: true }, Text("b")); t!(Markup[" /"]: ";,|/+" => Text(";,|/+")); t!(Markup[" /"]: "=-a" => Eq, Minus, Text("a")); t!(Markup[" "]: "#123" => Text("#123")); // Test text ends. t!(Markup[""]: "hello " => Text("hello"), Space(0)); - t!(Markup[""]: "hello~" => Text("hello"), Tilde); + t!(Markup[""]: "hello~" => Text("hello"), Shorthand('\u{00A0}')); } #[test] @@ -924,10 +927,10 @@ mod tests { t!(Markup: "_" => Underscore); t!(Markup[""]: "===" => Eq, Eq, Eq); t!(Markup["a1/"]: "= " => Eq, Space(0)); - t!(Markup[" "]: r"\" => Backslash); - t!(Markup: "~" => Tilde); - t!(Markup["a1/"]: "-?" => HyphQuest); - t!(Markup["a "]: r"a--" => Text("a"), Hyph2); + t!(Markup[" "]: r"\" => Linebreak); + t!(Markup: "~" => Shorthand('\u{00A0}')); + t!(Markup["a1/"]: "-?" => Shorthand('\u{00AD}')); + t!(Markup["a "]: r"a--" => Text("a"), Shorthand('\u{2013}')); t!(Markup["a1/"]: "- " => Minus, Space(0)); t!(Markup[" "]: "+" => Plus); t!(Markup[" "]: "1." => EnumNumbering(1)); diff --git a/src/source.rs b/src/source.rs index 8e22c01d..69e72d6b 100644 --- a/src/source.rs +++ b/src/source.rs @@ -10,7 +10,7 @@ use unscanny::Scanner; use crate::diag::SourceResult; use crate::parse::{is_newline, parse, reparse}; -use crate::syntax::ast::MarkupNode; +use crate::syntax::ast::Markup; use crate::syntax::{Span, SyntaxNode}; use crate::util::{PathExt, StrExt}; @@ -66,7 +66,7 @@ impl Source { } /// The root node of the file's typed abstract syntax tree. - pub fn ast(&self) -> SourceResult<MarkupNode> { + pub fn ast(&self) -> SourceResult<Markup> { let errors = self.root.errors(); if errors.is_empty() { Ok(self.root.cast().expect("root node must be markup")) diff --git a/src/syntax/ast.rs b/src/syntax/ast.rs index aa590da2..ecfa9a5b 100644 --- a/src/syntax/ast.rs +++ b/src/syntax/ast.rs @@ -5,8 +5,7 @@ use std::num::NonZeroUsize; use std::ops::Deref; -use super::{NodeData, NodeKind, Span, SyntaxNode}; -use crate::geom::{AngleUnit, LengthUnit}; +use super::{NodeData, NodeKind, RawKind, Span, SyntaxNode, Unit}; use crate::util::EcoString; /// A typed AST node. @@ -25,10 +24,7 @@ pub trait TypedNode: Sized { macro_rules! node { ($(#[$attr:meta])* $name:ident) => { - node!{$(#[$attr])* $name: $name} - }; - ($(#[$attr:meta])* $name:ident: $variant:ident) => { - node!{$(#[$attr])* $name: NodeKind::$variant} + node!{ $(#[$attr])* $name: NodeKind::$name { .. } } }; ($(#[$attr:meta])* $name:ident: $variants:pat) => { #[derive(Debug, Clone, PartialEq, Hash)] @@ -54,254 +50,296 @@ macro_rules! node { node! { /// The syntactical root capable of representing a full parsed document. - MarkupNode: NodeKind::Markup { .. } + Markup } -impl MarkupNode { +impl Markup { /// The children. - pub fn items(&self) -> impl Iterator<Item = MarkupItem> + '_ { + pub fn children(&self) -> impl Iterator<Item = MarkupNode> + '_ { self.0.children().filter_map(SyntaxNode::cast) } } /// A single piece of markup. #[derive(Debug, Clone, PartialEq)] -pub enum MarkupItem { +pub enum MarkupNode { /// Whitespace containing less than two newlines. - Space, + Space(Space), /// A forced line break. - Linebreak, - /// A paragraph break: Two or more newlines. - Parbreak, + Linebreak(Linebreak), /// Plain text. - Text(EcoString), + Text(Text), + /// An escape sequence: `\#`, `\u{1F5FA}`. + Escape(Escape), + /// A shorthand for a unicode codepoint. For example, `~` for non-breaking + /// space or `-?` for a soft hyphen. + Shorthand(Shorthand), /// A smart quote: `'` or `"`. - Quote { double: bool }, - /// Strong content: `*Strong*`. - Strong(StrongNode), - /// Emphasized content: `_Emphasized_`. - Emph(EmphNode), - /// A hyperlink: `https://typst.org`. - Link(EcoString), + SmartQuote(SmartQuote), + /// Strong markup: `*Strong*`. + Strong(Strong), + /// Emphasized markup: `_Emphasized_`. + Emph(Emph), /// A raw block with optional syntax highlighting: `` `...` ``. - Raw(RawNode), - /// A math formula: `$x$`, `$ x^2 $`. - Math(MathNode), + Raw(Raw), + /// A hyperlink: `https://typst.org`. + Link(Link), + /// A label: `<label>`. + Label(Label), + /// A reference: `@target`. + Ref(Ref), /// A section heading: `= Introduction`. - Heading(HeadingNode), + Heading(Heading), /// An item in an unordered list: `- ...`. List(ListItem), /// An item in an enumeration (ordered list): `+ ...` or `1. ...`. Enum(EnumItem), /// An item in a description list: `/ Term: Details`. Desc(DescItem), - /// A label: `<label>`. - Label(EcoString), - /// A reference: `@label`. - Ref(EcoString), + /// A math formula: `$x$`, `$ x^2 $`. + Math(Math), /// An expression. Expr(Expr), } -impl TypedNode for MarkupItem { +impl TypedNode for MarkupNode { fn from_untyped(node: &SyntaxNode) -> Option<Self> { match node.kind() { - NodeKind::Space { newlines: (2 ..) } => Some(Self::Parbreak), - NodeKind::Space { .. } => Some(Self::Space), - NodeKind::Backslash => Some(Self::Linebreak), - NodeKind::Text(s) => Some(Self::Text(s.clone())), - NodeKind::Escape(c) => Some(Self::Text((*c).into())), - NodeKind::Tilde => Some(Self::Text('\u{00A0}'.into())), - NodeKind::HyphQuest => Some(Self::Text('\u{00AD}'.into())), - NodeKind::Hyph2 => Some(Self::Text('\u{2013}'.into())), - NodeKind::Hyph3 => Some(Self::Text('\u{2014}'.into())), - NodeKind::Dot3 => Some(Self::Text('\u{2026}'.into())), - NodeKind::Quote { double } => Some(Self::Quote { double: *double }), + NodeKind::Space { .. } => node.cast().map(Self::Space), + NodeKind::Linebreak => node.cast().map(Self::Linebreak), + NodeKind::Text(_) => node.cast().map(Self::Text), + NodeKind::Escape(_) => node.cast().map(Self::Escape), + NodeKind::Shorthand(_) => node.cast().map(Self::Shorthand), + NodeKind::SmartQuote { .. } => node.cast().map(Self::SmartQuote), NodeKind::Strong => node.cast().map(Self::Strong), NodeKind::Emph => node.cast().map(Self::Emph), - NodeKind::Link(url) => Some(Self::Link(url.clone())), - NodeKind::Raw(raw) => Some(Self::Raw(raw.as_ref().clone())), - NodeKind::Math => node.cast().map(Self::Math), + NodeKind::Raw(_) => node.cast().map(Self::Raw), + NodeKind::Link(_) => node.cast().map(Self::Link), + NodeKind::Label(_) => node.cast().map(Self::Label), + NodeKind::Ref(_) => node.cast().map(Self::Ref), NodeKind::Heading => node.cast().map(Self::Heading), NodeKind::ListItem => node.cast().map(Self::List), NodeKind::EnumItem => node.cast().map(Self::Enum), NodeKind::DescItem => node.cast().map(Self::Desc), - NodeKind::Label(v) => Some(Self::Label(v.clone())), - NodeKind::Ref(v) => Some(Self::Ref(v.clone())), + NodeKind::Math => node.cast().map(Self::Math), _ => node.cast().map(Self::Expr), } } fn as_untyped(&self) -> &SyntaxNode { - unimplemented!("MarkupNode::as_untyped") + match self { + Self::Space(v) => v.as_untyped(), + Self::Linebreak(v) => v.as_untyped(), + Self::Text(v) => v.as_untyped(), + Self::Escape(v) => v.as_untyped(), + Self::Shorthand(v) => v.as_untyped(), + Self::SmartQuote(v) => v.as_untyped(), + Self::Strong(v) => v.as_untyped(), + Self::Emph(v) => v.as_untyped(), + Self::Raw(v) => v.as_untyped(), + Self::Link(v) => v.as_untyped(), + Self::Label(v) => v.as_untyped(), + Self::Ref(v) => v.as_untyped(), + Self::Heading(v) => v.as_untyped(), + Self::List(v) => v.as_untyped(), + Self::Enum(v) => v.as_untyped(), + Self::Desc(v) => v.as_untyped(), + Self::Math(v) => v.as_untyped(), + Self::Expr(v) => v.as_untyped(), + } } } node! { - /// Strong content: `*Strong*`. - StrongNode: Strong + /// Whitespace. + Space } -impl StrongNode { - /// The contents of the strong node. - pub fn body(&self) -> MarkupNode { - self.0.cast_first_child().expect("strong node is missing markup body") +impl Space { + /// Get the number of newlines. + pub fn newlines(&self) -> usize { + match self.0.kind() { + &NodeKind::Space { newlines } => newlines, + _ => panic!("space is of wrong kind"), + } } } node! { - /// Emphasized content: `_Emphasized_`. - EmphNode: Emph + /// A forced line break. + Linebreak } -impl EmphNode { - /// The contents of the emphasis node. - pub fn body(&self) -> MarkupNode { - self.0 - .cast_first_child() - .expect("emphasis node is missing markup body") - } +node! { + /// Plain text. + Text } -/// A raw block with optional syntax highlighting: `` `...` ``. -#[derive(Debug, Clone, PartialEq, Hash)] -pub struct RawNode { - /// An optional identifier specifying the language to syntax-highlight in. - pub lang: Option<EcoString>, - /// The raw text, determined as the raw string between the backticks trimmed - /// according to the above rules. - pub text: EcoString, - /// Whether the element is block-level, that is, it has 3+ backticks - /// and contains at least one newline. - pub block: bool, +impl Text { + /// Get the text. + pub fn get(&self) -> &EcoString { + match self.0.kind() { + NodeKind::Text(v) => v, + _ => panic!("text is of wrong kind"), + } + } } node! { - /// A math formula: `$x$`, `$ x^2 $`. - MathNode: NodeKind::Math { .. } + /// An escape sequence: `\#`, `\u{1F5FA}`. + Escape } -impl MathNode { - /// The children. - pub fn items(&self) -> impl Iterator<Item = MathItem> + '_ { - self.0.children().filter_map(SyntaxNode::cast) +impl Escape { + /// Get the escaped character. + pub fn get(&self) -> char { + match self.0.kind() { + &NodeKind::Escape(v) => v, + _ => panic!("escape is of wrong kind"), + } } } -/// A single piece of a math formula. -#[derive(Debug, Clone, PartialEq, Hash)] -pub enum MathItem { - /// Whitespace. - Space, - /// A forced line break. - Linebreak, - /// An atom: `x`, `+`, `12`. - Atom(EcoString), - /// A base with an optional sub- and superscript: `a_1^2`. - Script(ScriptNode), - /// A fraction: `x/2`. - Frac(FracNode), - /// An alignment indicator: `&`, `&&`. - Align(AlignNode), - /// Grouped mathematical material. - Group(MathNode), - /// An expression. - Expr(Expr), +node! { + /// A shorthand for a unicode codepoint. For example, `~` for non-breaking + /// space or `-?` for a soft hyphen. + Shorthand } -impl TypedNode for MathItem { - fn from_untyped(node: &SyntaxNode) -> Option<Self> { - match node.kind() { - NodeKind::Space { .. } => Some(Self::Space), - NodeKind::LeftBrace => Some(Self::Atom('{'.into())), - NodeKind::RightBrace => Some(Self::Atom('}'.into())), - NodeKind::LeftBracket => Some(Self::Atom('['.into())), - NodeKind::RightBracket => Some(Self::Atom(']'.into())), - NodeKind::LeftParen => Some(Self::Atom('('.into())), - NodeKind::RightParen => Some(Self::Atom(')'.into())), - NodeKind::Backslash => Some(Self::Linebreak), - NodeKind::Escape(c) => Some(Self::Atom((*c).into())), - NodeKind::Atom(atom) => Some(Self::Atom(atom.clone())), - NodeKind::Script => node.cast().map(Self::Script), - NodeKind::Frac => node.cast().map(Self::Frac), - NodeKind::Align => node.cast().map(Self::Align), - NodeKind::Math => node.cast().map(Self::Group), - _ => node.cast().map(Self::Expr), +impl Shorthand { + /// Get the shorthanded character. + pub fn get(&self) -> char { + match self.0.kind() { + &NodeKind::Shorthand(v) => v, + _ => panic!("shorthand is of wrong kind"), } } +} - fn as_untyped(&self) -> &SyntaxNode { - unimplemented!("MathNode::as_untyped") +node! { + /// A smart quote: `'` or `"`. + SmartQuote +} + +impl SmartQuote { + /// Whether this is a double quote. + pub fn double(&self) -> bool { + match self.0.kind() { + &NodeKind::SmartQuote { double } => double, + _ => panic!("smart quote is of wrong kind"), + } } } node! { - /// A base with an optional sub- and superscript in a formula: `a_1^2`. - ScriptNode: Script + /// Strong content: `*Strong*`. + Strong } -impl ScriptNode { - /// The base of the script. - pub fn base(&self) -> MathItem { - self.0.cast_first_child().expect("subscript is missing base") +impl Strong { + /// The contents of the strong node. + pub fn body(&self) -> Markup { + self.0.cast_first_child().expect("strong node is missing markup body") } +} - /// The subscript. - pub fn sub(&self) -> Option<MathItem> { +node! { + /// Emphasized content: `_Emphasized_`. + Emph +} + +impl Emph { + /// The contents of the emphasis node. + pub fn body(&self) -> Markup { self.0 - .children() - .skip_while(|node| !matches!(node.kind(), NodeKind::Underscore)) - .nth(1) - .map(|node| node.cast().expect("script node has invalid subscript")) + .cast_first_child() + .expect("emphasis node is missing markup body") } +} - /// The superscript. - pub fn sup(&self) -> Option<MathItem> { - self.0 - .children() - .skip_while(|node| !matches!(node.kind(), NodeKind::Hat)) - .nth(1) - .map(|node| node.cast().expect("script node has invalid superscript")) +node! { + /// A raw block with optional syntax highlighting: `` `...` ``. + Raw +} + +impl Raw { + /// The raw text. + pub fn text(&self) -> &EcoString { + &self.get().text + } + + /// An optional identifier specifying the language to syntax-highlight in. + pub fn lang(&self) -> Option<&EcoString> { + self.get().lang.as_ref() + } + + /// Whether the raw block is block-level. + pub fn block(&self) -> bool { + self.get().block + } + + /// The raw fields. + fn get(&self) -> &RawKind { + match self.0.kind() { + NodeKind::Raw(v) => v.as_ref(), + _ => panic!("raw is of wrong kind"), + } } } node! { - /// A fraction in a formula: `x/2` - FracNode: Frac + /// A hyperlink: `https://typst.org`. + Link } -impl FracNode { - /// The numerator. - pub fn num(&self) -> MathItem { - self.0.cast_first_child().expect("fraction is missing numerator") +impl Link { + /// Get the URL. + pub fn url(&self) -> &EcoString { + match self.0.kind() { + NodeKind::Link(url) => url, + _ => panic!("link is of wrong kind"), + } } +} - /// The denominator. - pub fn denom(&self) -> MathItem { - self.0.cast_last_child().expect("fraction is missing denominator") +node! { + /// A label: `<label>`. + Label +} + +impl Label { + /// Get the label. + pub fn get(&self) -> &EcoString { + match self.0.kind() { + NodeKind::Label(v) => v, + _ => panic!("label is of wrong kind"), + } } } node! { - /// A math alignment indicator: `&`, `&&`. - AlignNode: Align + /// A reference: `@target`. + Ref } -impl AlignNode { - /// The number of ampersands. - pub fn count(&self) -> usize { - self.0.children().filter(|n| n.kind() == &NodeKind::Amp).count() +impl Ref { + /// Get the target. + pub fn get(&self) -> &EcoString { + match self.0.kind() { + NodeKind::Ref(v) => v, + _ => panic!("reference is of wrong kind"), + } } } node! { /// A section heading: `= Introduction`. - HeadingNode: Heading + Heading } -impl HeadingNode { +impl Heading { /// The contents of the heading. - pub fn body(&self) -> MarkupNode { + pub fn body(&self) -> Markup { self.0.cast_first_child().expect("heading is missing markup body") } @@ -318,19 +356,19 @@ impl HeadingNode { node! { /// An item in an unordered list: `- ...`. - ListItem: ListItem + ListItem } impl ListItem { /// The contents of the list item. - pub fn body(&self) -> MarkupNode { + pub fn body(&self) -> Markup { self.0.cast_first_child().expect("list item is missing body") } } node! { /// An item in an enumeration (ordered list): `1. ...`. - EnumItem: EnumItem + EnumItem } impl EnumItem { @@ -343,32 +381,171 @@ impl EnumItem { } /// The contents of the list item. - pub fn body(&self) -> MarkupNode { + pub fn body(&self) -> Markup { self.0.cast_first_child().expect("enum item is missing body") } } node! { /// An item in a description list: `/ Term: Details`. - DescItem: DescItem + DescItem } impl DescItem { /// The term described by the item. - pub fn term(&self) -> MarkupNode { + pub fn term(&self) -> Markup { self.0 .cast_first_child() .expect("description list item is missing term") } /// The description of the term. - pub fn body(&self) -> MarkupNode { + pub fn body(&self) -> Markup { self.0 .cast_last_child() .expect("description list item is missing body") } } +node! { + /// A math formula: `$x$`, `$ x^2 $`. + Math +} + +impl Math { + /// The children. + pub fn children(&self) -> impl Iterator<Item = MathNode> + '_ { + self.0.children().filter_map(SyntaxNode::cast) + } +} + +/// A single piece of a math formula. +#[derive(Debug, Clone, PartialEq, Hash)] +pub enum MathNode { + /// Whitespace. + Space(Space), + /// A forced line break. + Linebreak(Linebreak), + /// An escape sequence: `\#`, `\u{1F5FA}`. + Escape(Escape), + /// A atom: `x`, `+`, `12`. + Atom(Atom), + /// A base with an optional sub- and superscript: `a_1^2`. + Script(Script), + /// A fraction: `x/2`. + Frac(Frac), + /// An alignment indicator: `&`, `&&`. + Align(Align), + /// Grouped mathematical material. + Group(Math), + /// An expression. + Expr(Expr), +} + +impl TypedNode for MathNode { + fn from_untyped(node: &SyntaxNode) -> Option<Self> { + match node.kind() { + NodeKind::Space { .. } => node.cast().map(Self::Space), + NodeKind::Linebreak => node.cast().map(Self::Linebreak), + NodeKind::Escape(_) => node.cast().map(Self::Escape), + NodeKind::Atom(_) => node.cast().map(Self::Atom), + NodeKind::Script => node.cast().map(Self::Script), + NodeKind::Frac => node.cast().map(Self::Frac), + NodeKind::Align => node.cast().map(Self::Align), + NodeKind::Math => node.cast().map(Self::Group), + _ => node.cast().map(Self::Expr), + } + } + + fn as_untyped(&self) -> &SyntaxNode { + match self { + Self::Space(v) => v.as_untyped(), + Self::Linebreak(v) => v.as_untyped(), + Self::Escape(v) => v.as_untyped(), + Self::Atom(v) => v.as_untyped(), + Self::Script(v) => v.as_untyped(), + Self::Frac(v) => v.as_untyped(), + Self::Align(v) => v.as_untyped(), + Self::Group(v) => v.as_untyped(), + Self::Expr(v) => v.as_untyped(), + } + } +} + +node! { + /// A atom in a formula: `x`, `+`, `12`. + Atom +} + +impl Atom { + /// Get the atom's text. + pub fn get(&self) -> &EcoString { + match self.0.kind() { + NodeKind::Atom(v) => v, + _ => panic!("atom is of wrong kind"), + } + } +} + +node! { + /// A base with an optional sub- and superscript in a formula: `a_1^2`. + Script +} + +impl Script { + /// The base of the script. + pub fn base(&self) -> MathNode { + self.0.cast_first_child().expect("script node is missing base") + } + + /// The subscript. + pub fn sub(&self) -> Option<MathNode> { + self.0 + .children() + .skip_while(|node| !matches!(node.kind(), NodeKind::Underscore)) + .nth(1) + .map(|node| node.cast().expect("script node has invalid subscript")) + } + + /// The superscript. + pub fn sup(&self) -> Option<MathNode> { + self.0 + .children() + .skip_while(|node| !matches!(node.kind(), NodeKind::Hat)) + .nth(1) + .map(|node| node.cast().expect("script node has invalid superscript")) + } +} + +node! { + /// A fraction in a formula: `x/2` + Frac +} + +impl Frac { + /// The numerator. + pub fn num(&self) -> MathNode { + self.0.cast_first_child().expect("fraction is missing numerator") + } + + /// The denominator. + pub fn denom(&self) -> MathNode { + self.0.cast_last_child().expect("fraction is missing denominator") + } +} + +node! { + /// A math alignment indicator: `&`, `&&`. + Align +} + +impl Align { + /// The number of ampersands. + pub fn count(&self) -> usize { + self.0.children().filter(|n| n.kind() == &NodeKind::Amp).count() + } +} + /// An expression. #[derive(Debug, Clone, PartialEq, Hash)] pub enum Expr { @@ -381,15 +558,15 @@ pub enum Expr { /// A content block: `[*Hi* there!]`. Content(ContentBlock), /// A grouped expression: `(1 + 2)`. - Group(GroupExpr), + Parenthesized(Parenthesized), /// An array expression: `(1, "hi", 12cm)`. - Array(ArrayExpr), + Array(Array), /// A dictionary expression: `(thickness: 3pt, pattern: dashed)`. - Dict(DictExpr), + Dict(Dict), /// A unary operation: `-x`. - Unary(UnaryExpr), + Unary(Unary), /// A binary operation: `a + b`. - Binary(BinaryExpr), + Binary(Binary), /// A field access: `properties.age`. FieldAccess(FieldAccess), /// An invocation of a function: `f(x, y)`. @@ -397,31 +574,31 @@ pub enum Expr { /// An invocation of a method: `array.push(v)`. MethodCall(MethodCall), /// A closure expression: `(x, y) => z`. - Closure(ClosureExpr), - /// A let expression: `let x = 1`. - Let(LetExpr), - /// A set expression: `set text(...)`. - Set(SetExpr), - /// A show expression: `show node: heading as [*{nody.body}*]`. - Show(ShowExpr), - /// A wrap expression: `wrap body in columns(2, body)`. - Wrap(WrapExpr), - /// An if-else expression: `if x { y } else { z }`. - If(IfExpr), - /// A while loop expression: `while x { y }`. - While(WhileExpr), - /// A for loop expression: `for x in y { z }`. - For(ForExpr), - /// An import expression: `import a, b, c from "utils.typ"`. - Import(ImportExpr), - /// An include expression: `include "chapter1.typ"`. - Include(IncludeExpr), - /// A break expression: `break`. - Break(BreakExpr), - /// A continue expression: `continue`. - Continue(ContinueExpr), - /// A return expression: `return`. - Return(ReturnExpr), + Closure(Closure), + /// A let binding: `let x = 1`. + Let(LetBinding), + /// A set rule: `set text(...)`. + Set(SetRule), + /// A show rule: `show node: heading as [*{nody.body}*]`. + Show(ShowRule), + /// A wrap rule: `wrap body in columns(2, body)`. + Wrap(WrapRule), + /// An if-else conditional: `if x { y } else { z }`. + Conditional(Conditional), + /// A while loop: `while x { y }`. + While(WhileLoop), + /// A for loop: `for x in y { z }`. + For(ForLoop), + /// A module import: `import a, b, c from "utils.typ"`. + Import(ModuleImport), + /// A module include: `include "chapter1.typ"`. + Include(ModuleInclude), + /// A break statement: `break`. + Break(BreakStmt), + /// A continue statement: `continue`. + Continue(ContinueStmt), + /// A return statement: `return`, `return x + 1`. + Return(ReturnStmt), } impl TypedNode for Expr { @@ -430,27 +607,27 @@ impl TypedNode for Expr { NodeKind::Ident(_) => node.cast().map(Self::Ident), NodeKind::CodeBlock => node.cast().map(Self::Code), NodeKind::ContentBlock => node.cast().map(Self::Content), - NodeKind::GroupExpr => node.cast().map(Self::Group), - NodeKind::ArrayExpr => node.cast().map(Self::Array), - NodeKind::DictExpr => node.cast().map(Self::Dict), - NodeKind::UnaryExpr => node.cast().map(Self::Unary), - NodeKind::BinaryExpr => node.cast().map(Self::Binary), + NodeKind::Parenthesized => node.cast().map(Self::Parenthesized), + NodeKind::Array => node.cast().map(Self::Array), + NodeKind::Dict => node.cast().map(Self::Dict), + NodeKind::Unary => node.cast().map(Self::Unary), + NodeKind::Binary => node.cast().map(Self::Binary), NodeKind::FieldAccess => node.cast().map(Self::FieldAccess), NodeKind::FuncCall => node.cast().map(Self::FuncCall), NodeKind::MethodCall => node.cast().map(Self::MethodCall), - NodeKind::ClosureExpr => node.cast().map(Self::Closure), - NodeKind::LetExpr => node.cast().map(Self::Let), - NodeKind::SetExpr => node.cast().map(Self::Set), - NodeKind::ShowExpr => node.cast().map(Self::Show), - NodeKind::WrapExpr => node.cast().map(Self::Wrap), - NodeKind::IfExpr => node.cast().map(Self::If), - NodeKind::WhileExpr => node.cast().map(Self::While), - NodeKind::ForExpr => node.cast().map(Self::For), - NodeKind::ImportExpr => node.cast().map(Self::Import), - NodeKind::IncludeExpr => node.cast().map(Self::Include), - NodeKind::BreakExpr => node.cast().map(Self::Break), - NodeKind::ContinueExpr => node.cast().map(Self::Continue), - NodeKind::ReturnExpr => node.cast().map(Self::Return), + NodeKind::Closure => node.cast().map(Self::Closure), + NodeKind::LetBinding => node.cast().map(Self::Let), + NodeKind::SetRule => node.cast().map(Self::Set), + NodeKind::ShowRule => node.cast().map(Self::Show), + NodeKind::WrapRule => node.cast().map(Self::Wrap), + NodeKind::Conditional => node.cast().map(Self::Conditional), + NodeKind::WhileLoop => node.cast().map(Self::While), + NodeKind::ForLoop => node.cast().map(Self::For), + NodeKind::ModuleImport => node.cast().map(Self::Import), + NodeKind::ModuleInclude => node.cast().map(Self::Include), + NodeKind::BreakStmt => node.cast().map(Self::Break), + NodeKind::ContinueStmt => node.cast().map(Self::Continue), + NodeKind::ReturnStmt => node.cast().map(Self::Return), _ => node.cast().map(Self::Lit), } } @@ -463,7 +640,7 @@ impl TypedNode for Expr { Self::Ident(v) => v.as_untyped(), Self::Array(v) => v.as_untyped(), Self::Dict(v) => v.as_untyped(), - Self::Group(v) => v.as_untyped(), + Self::Parenthesized(v) => v.as_untyped(), Self::Unary(v) => v.as_untyped(), Self::Binary(v) => v.as_untyped(), Self::FieldAccess(v) => v.as_untyped(), @@ -474,7 +651,7 @@ impl TypedNode for Expr { Self::Set(v) => v.as_untyped(), Self::Show(v) => v.as_untyped(), Self::Wrap(v) => v.as_untyped(), - Self::If(v) => v.as_untyped(), + Self::Conditional(v) => v.as_untyped(), Self::While(v) => v.as_untyped(), Self::For(v) => v.as_untyped(), Self::Import(v) => v.as_untyped(), @@ -497,7 +674,7 @@ impl Expr { | Self::Set(_) | Self::Show(_) | Self::Wrap(_) - | Self::If(_) + | Self::Conditional(_) | Self::While(_) | Self::For(_) | Self::Import(_) @@ -552,24 +729,9 @@ pub enum LitKind { Str(EcoString), } -/// Unit of a numeric value. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum Unit { - /// An absolute length unit. - Length(LengthUnit), - /// An angular unit. - Angle(AngleUnit), - /// Font-relative: `1em` is the same as the font size. - Em, - /// Fractions: `fr`. - Fr, - /// Percentage: `%`. - Percent, -} - node! { /// A code block: `{ let x = 1; x + 2 }`. - CodeBlock: CodeBlock + CodeBlock } impl CodeBlock { @@ -581,46 +743,48 @@ impl CodeBlock { node! { /// A content block: `[*Hi* there!]`. - ContentBlock: ContentBlock + ContentBlock } impl ContentBlock { /// The contained markup. - pub fn body(&self) -> MarkupNode { - self.0.cast_first_child().expect("content is missing body") + pub fn body(&self) -> Markup { + self.0.cast_first_child().expect("content block is missing body") } } node! { - /// A grouped expression: `(1 + 2)`. - GroupExpr: GroupExpr + /// A parenthesized expression: `(1 + 2)`. + Parenthesized } -impl GroupExpr { +impl Parenthesized { /// The wrapped expression. pub fn expr(&self) -> Expr { - self.0.cast_first_child().expect("group is missing expression") + self.0 + .cast_first_child() + .expect("parenthesized expression is missing expression") } } node! { - /// An array expression: `(1, "hi", 12cm)`. - ArrayExpr: ArrayExpr + /// An array: `(1, "hi", 12cm)`. + Array } -impl ArrayExpr { - /// The array items. +impl Array { + /// The array's items. pub fn items(&self) -> impl Iterator<Item = ArrayItem> + '_ { self.0.children().filter_map(SyntaxNode::cast) } } -/// An item in an array expresssion. +/// An item in an array. #[derive(Debug, Clone, PartialEq, Hash)] pub enum ArrayItem { - /// A bare value: `12`. + /// A bare expression: `12`. Pos(Expr), - /// A spreaded value: `..things`. + /// A spreaded expression: `..things`. Spread(Expr), } @@ -641,12 +805,12 @@ impl TypedNode for ArrayItem { } node! { - /// A dictionary expression: `(thickness: 3pt, pattern: dashed)`. - DictExpr: DictExpr + /// A dictionary: `(thickness: 3pt, pattern: dashed)`. + Dict } -impl DictExpr { - /// The named dictionary items. +impl Dict { + /// The dictionary's items. pub fn items(&self) -> impl Iterator<Item = DictItem> + '_ { self.0.children().filter_map(SyntaxNode::cast) } @@ -659,7 +823,7 @@ pub enum DictItem { Named(Named), /// A keyed pair: `"spacy key": true`. Keyed(Keyed), - /// A spreaded value: `..things`. + /// A spreaded expression: `..things`. Spread(Expr), } @@ -724,21 +888,21 @@ impl Keyed { node! { /// A unary operation: `-x`. - UnaryExpr: UnaryExpr + Unary } -impl UnaryExpr { +impl Unary { /// The operator: `-`. pub fn op(&self) -> UnOp { self.0 .children() .find_map(|node| UnOp::from_token(node.kind())) - .expect("unary expression is missing operator") + .expect("unary operation is missing operator") } /// The expression to operate on: `x`. pub fn expr(&self) -> Expr { - self.0.cast_last_child().expect("unary expression is missing child") + self.0.cast_last_child().expect("unary operation is missing child") } } @@ -784,10 +948,10 @@ impl UnOp { node! { /// A binary operation: `a + b`. - BinaryExpr: BinaryExpr + Binary } -impl BinaryExpr { +impl Binary { /// The binary operator: `+`. pub fn op(&self) -> BinOp { let mut not = false; @@ -801,21 +965,21 @@ impl BinaryExpr { NodeKind::In if not => Some(BinOp::NotIn), _ => BinOp::from_token(node.kind()), }) - .expect("binary expression is missing operator") + .expect("binary operation is missing operator") } /// The left-hand side of the operation: `a`. pub fn lhs(&self) -> Expr { self.0 .cast_first_child() - .expect("binary expression is missing left-hand side") + .expect("binary operation is missing left-hand side") } /// The right-hand side of the operation: `b`. pub fn rhs(&self) -> Expr { self.0 .cast_last_child() - .expect("binary expression is missing right-hand side") + .expect("binary operation is missing right-hand side") } } @@ -975,24 +1139,24 @@ pub enum Assoc { node! { /// A field access: `properties.age`. - FieldAccess: FieldAccess + FieldAccess } impl FieldAccess { - /// The object with the field. - pub fn object(&self) -> Expr { + /// The expression to access the field on. + pub fn target(&self) -> Expr { self.0.cast_first_child().expect("field access is missing object") } /// The name of the field. pub fn field(&self) -> Ident { - self.0.cast_last_child().expect("field access call is missing name") + self.0.cast_last_child().expect("field access is missing name") } } node! { /// An invocation of a function: `f(x, y)`. - FuncCall: FuncCall + FuncCall } impl FuncCall { @@ -1002,7 +1166,7 @@ impl FuncCall { } /// The arguments to the function. - pub fn args(&self) -> CallArgs { + pub fn args(&self) -> Args { self.0 .cast_last_child() .expect("function call is missing argument list") @@ -1011,13 +1175,13 @@ impl FuncCall { node! { /// An invocation of a method: `array.push(v)`. - MethodCall: MethodCall + MethodCall } impl MethodCall { - /// The value to call the method on. - pub fn receiver(&self) -> Expr { - self.0.cast_first_child().expect("method call is missing callee") + /// The expresion to call the method on. + pub fn target(&self) -> Expr { + self.0.cast_first_child().expect("method call is missing target") } /// The name of the method. @@ -1026,7 +1190,7 @@ impl MethodCall { } /// The arguments to the method. - pub fn args(&self) -> CallArgs { + pub fn args(&self) -> Args { self.0 .cast_last_child() .expect("method call is missing argument list") @@ -1035,19 +1199,19 @@ impl MethodCall { node! { /// The arguments to a function: `12, draw: false`. - CallArgs + Args } -impl CallArgs { +impl Args { /// The positional and named arguments. - pub fn items(&self) -> impl Iterator<Item = CallArg> + '_ { + pub fn items(&self) -> impl Iterator<Item = Arg> + '_ { self.0.children().filter_map(SyntaxNode::cast) } } /// An argument to a function call. #[derive(Debug, Clone, PartialEq, Hash)] -pub enum CallArg { +pub enum Arg { /// A positional argument: `12`. Pos(Expr), /// A named argument: `draw: false`. @@ -1056,7 +1220,7 @@ pub enum CallArg { Spread(Expr), } -impl TypedNode for CallArg { +impl TypedNode for Arg { fn from_untyped(node: &SyntaxNode) -> Option<Self> { match node.kind() { NodeKind::Named => node.cast().map(Self::Named), @@ -1076,10 +1240,10 @@ impl TypedNode for CallArg { node! { /// A closure expression: `(x, y) => z`. - ClosureExpr: ClosureExpr + Closure } -impl ClosureExpr { +impl Closure { /// The name of the closure. /// /// This only exists if you use the function syntax sugar: `let f(x) = y`. @@ -1088,10 +1252,10 @@ impl ClosureExpr { } /// The parameter bindings. - pub fn params(&self) -> impl Iterator<Item = ClosureParam> + '_ { + pub fn params(&self) -> impl Iterator<Item = Param> + '_ { self.0 .children() - .find(|x| x.kind() == &NodeKind::ClosureParams) + .find(|x| x.kind() == &NodeKind::Params) .expect("closure is missing parameter list") .children() .filter_map(SyntaxNode::cast) @@ -1105,7 +1269,7 @@ impl ClosureExpr { /// A parameter to a closure. #[derive(Debug, Clone, PartialEq, Hash)] -pub enum ClosureParam { +pub enum Param { /// A positional parameter: `x`. Pos(Ident), /// A named parameter with a default value: `draw: false`. @@ -1114,7 +1278,7 @@ pub enum ClosureParam { Sink(Ident), } -impl TypedNode for ClosureParam { +impl TypedNode for Param { fn from_untyped(node: &SyntaxNode) -> Option<Self> { match node.kind() { NodeKind::Ident(_) => node.cast().map(Self::Pos), @@ -1134,11 +1298,11 @@ impl TypedNode for ClosureParam { } node! { - /// A let expression: `let x = 1`. - LetExpr + /// A let binding: `let x = 1`. + LetBinding } -impl LetExpr { +impl LetBinding { /// The binding to assign to. pub fn binding(&self) -> Ident { match self.0.cast_first_child() { @@ -1146,7 +1310,7 @@ impl LetExpr { Some(Expr::Closure(closure)) => { closure.name().expect("let-bound closure is missing name") } - _ => panic!("let expression is missing binding"), + _ => panic!("let is missing binding"), } } @@ -1163,28 +1327,28 @@ impl LetExpr { } node! { - /// A set expression: `set text(...)`. - SetExpr + /// A set rule: `set text(...)`. + SetRule } -impl SetExpr { +impl SetRule { /// The function to set style properties for. pub fn target(&self) -> Ident { self.0.cast_first_child().expect("set rule is missing target") } /// The style properties to set. - pub fn args(&self) -> CallArgs { + pub fn args(&self) -> Args { self.0.cast_last_child().expect("set rule is missing argument list") } } node! { - /// A show expression: `show node: heading as [*{nody.body}*]`. - ShowExpr + /// A show rule: `show node: heading as [*{nody.body}*]`. + ShowRule } -impl ShowExpr { +impl ShowRule { /// The binding to assign to. pub fn binding(&self) -> Option<Ident> { let mut children = self.0.children(); @@ -1210,31 +1374,31 @@ impl ShowExpr { } node! { - /// A wrap expression: `wrap body in columns(2, body)`. - WrapExpr + /// A wrap rule: `wrap body in columns(2, body)`. + WrapRule } -impl WrapExpr { +impl WrapRule { /// The binding to assign the remaining markup to. pub fn binding(&self) -> Ident { - self.0.cast_first_child().expect("wrap expression is missing binding") + self.0.cast_first_child().expect("wrap rule is missing binding") } /// The expression to evaluate. pub fn body(&self) -> Expr { - self.0.cast_last_child().expect("wrap expression is missing body") + self.0.cast_last_child().expect("wrap rule is missing body") } } node! { - /// An if-else expression: `if x { y } else { z }`. - IfExpr + /// An if-else conditional: `if x { y } else { z }`. + Conditional } -impl IfExpr { +impl Conditional { /// The condition which selects the body to evaluate. pub fn condition(&self) -> Expr { - self.0.cast_first_child().expect("if expression is missing condition") + self.0.cast_first_child().expect("conditional is missing condition") } /// The expression to evaluate if the condition is true. @@ -1243,7 +1407,7 @@ impl IfExpr { .children() .filter_map(SyntaxNode::cast) .nth(1) - .expect("if expression is missing body") + .expect("conditional is missing body") } /// The expression to evaluate if the condition is false. @@ -1253,11 +1417,11 @@ impl IfExpr { } node! { - /// A while loop expression: `while x { y }`. - WhileExpr + /// A while loop: `while x { y }`. + WhileLoop } -impl WhileExpr { +impl WhileLoop { /// The condition which selects whether to evaluate the body. pub fn condition(&self) -> Expr { self.0.cast_first_child().expect("while loop is missing condition") @@ -1270,11 +1434,11 @@ impl WhileExpr { } node! { - /// A for loop expression: `for x in y { z }`. - ForExpr + /// A for loop: `for x in y { z }`. + ForLoop } -impl ForExpr { +impl ForLoop { /// The pattern to assign to. pub fn pattern(&self) -> ForPattern { self.0.cast_first_child().expect("for loop is missing pattern") @@ -1292,7 +1456,7 @@ impl ForExpr { } node! { - /// A for-in loop expression: `for x in y { z }`. + /// A for-in loop: `for x in y { z }`. ForPattern } @@ -1311,11 +1475,11 @@ impl ForPattern { } node! { - /// An import expression: `import a, b, c from "utils.typ"`. - ImportExpr + /// A module import: `import a, b, c from "utils.typ"`. + ModuleImport } -impl ImportExpr { +impl ModuleImport { /// The items to be imported. pub fn imports(&self) -> Imports { self.0 @@ -1328,12 +1492,12 @@ impl ImportExpr { } _ => None, }) - .expect("import is missing items") + .expect("module import is missing items") } /// The path to the file that should be imported. pub fn path(&self) -> Expr { - self.0.cast_last_child().expect("import is missing path") + self.0.cast_last_child().expect("module import is missing path") } } @@ -1347,33 +1511,33 @@ pub enum Imports { } node! { - /// An include expression: `include "chapter1.typ"`. - IncludeExpr + /// A module include: `include "chapter1.typ"`. + ModuleInclude } -impl IncludeExpr { +impl ModuleInclude { /// The path to the file that should be included. pub fn path(&self) -> Expr { - self.0.cast_last_child().expect("include is missing path") + self.0.cast_last_child().expect("module include is missing path") } } node! { /// A break expression: `break`. - BreakExpr + BreakStmt } node! { /// A continue expression: `continue`. - ContinueExpr + ContinueStmt } node! { /// A return expression: `return`, `return x + 1`. - ReturnExpr + ReturnStmt } -impl ReturnExpr { +impl ReturnStmt { /// The expression to return. pub fn body(&self) -> Option<Expr> { self.0.cast_last_child() @@ -1382,11 +1546,19 @@ impl ReturnExpr { node! { /// An identifier. - Ident: NodeKind::Ident(_) + Ident } impl Ident { - /// Take out the contained [`EcoString`]. + /// Get the identifier. + pub fn get(&self) -> &EcoString { + match self.0.kind() { + NodeKind::Ident(id) => id, + _ => panic!("identifier is of wrong kind"), + } + } + + /// Take out the container identifier. pub fn take(self) -> EcoString { match self.0 { SyntaxNode::Leaf(NodeData { kind: NodeKind::Ident(id), .. }) => id, @@ -1399,9 +1571,6 @@ impl Deref for Ident { type Target = str; fn deref(&self) -> &Self::Target { - match &self.0 { - SyntaxNode::Leaf(NodeData { kind: NodeKind::Ident(id), .. }) => id, - _ => panic!("identifier is of wrong kind"), - } + self.get() } } diff --git a/src/syntax/highlight.rs b/src/syntax/highlight.rs index 60d349d1..bfb36078 100644 --- a/src/syntax/highlight.rs +++ b/src/syntax/highlight.rs @@ -138,23 +138,21 @@ pub enum Category { /// An escape sequence. Escape, /// An easily typable shortcut to a unicode codepoint. - Shortcut, + Shorthand, /// A smart quote. - Quote, - /// Strong text. + SmartQuote, + /// Strong markup. Strong, - /// Emphasized text. + /// Emphasized markup. Emph, /// A hyperlink. Link, /// Raw text or code. Raw, - /// A full math formula. - Math, - /// The delimiters of a math formula. - MathDelimiter, - /// A symbol with special meaning in a math formula. - MathSymbol, + /// A label. + Label, + /// A reference. + Ref, /// A section heading. Heading, /// A full item of a list, enumeration or description list. @@ -163,10 +161,12 @@ pub enum Category { ListMarker, /// A term in a description list. ListTerm, - /// A label. - Label, - /// A reference. - Ref, + /// A full math formula. + Math, + /// The delimiters of a math formula. + MathDelimiter, + /// An operator with special meaning in a math formula. + MathOperator, /// A keyword. Keyword, /// A literal defined by a keyword like `none`, `auto` or a boolean. @@ -212,17 +212,10 @@ impl Category { _ => Some(Category::Operator), }, NodeKind::Underscore => match parent.kind() { - NodeKind::Script => Some(Category::MathSymbol), + NodeKind::Script => Some(Category::MathOperator), _ => None, }, NodeKind::Dollar => Some(Category::MathDelimiter), - NodeKind::Backslash => Some(Category::Shortcut), - NodeKind::Tilde => Some(Category::Shortcut), - NodeKind::HyphQuest => Some(Category::Shortcut), - NodeKind::Hyph2 => Some(Category::Shortcut), - NodeKind::Hyph3 => Some(Category::Shortcut), - NodeKind::Dot3 => Some(Category::Shortcut), - NodeKind::Quote { .. } => Some(Category::Quote), NodeKind::Plus => Some(match parent.kind() { NodeKind::EnumItem => Category::ListMarker, _ => Category::Operator, @@ -233,11 +226,11 @@ impl Category { }), NodeKind::Slash => Some(match parent.kind() { NodeKind::DescItem => Category::ListMarker, - NodeKind::Frac => Category::MathSymbol, + NodeKind::Frac => Category::MathOperator, _ => Category::Operator, }), - NodeKind::Hat => Some(Category::MathSymbol), - NodeKind::Amp => Some(Category::MathSymbol), + NodeKind::Hat => Some(Category::MathOperator), + NodeKind::Amp => Some(Category::MathOperator), NodeKind::Dot => Some(Category::Punctuation), NodeKind::Eq => match parent.kind() { NodeKind::Heading => None, @@ -291,32 +284,35 @@ impl Category { _ => None, }, NodeKind::Text(_) => None, + NodeKind::Linebreak => Some(Category::Escape), NodeKind::Escape(_) => Some(Category::Escape), + NodeKind::Shorthand(_) => Some(Category::Shorthand), + NodeKind::SmartQuote { .. } => Some(Category::SmartQuote), NodeKind::Strong => Some(Category::Strong), NodeKind::Emph => Some(Category::Emph), - NodeKind::Link(_) => Some(Category::Link), NodeKind::Raw(_) => Some(Category::Raw), - NodeKind::Math => Some(Category::Math), - NodeKind::Atom(_) => None, - NodeKind::Script => None, - NodeKind::Frac => None, - NodeKind::Align => None, + NodeKind::Link(_) => Some(Category::Link), + NodeKind::Label(_) => Some(Category::Label), + NodeKind::Ref(_) => Some(Category::Ref), NodeKind::Heading => Some(Category::Heading), NodeKind::ListItem => Some(Category::ListItem), NodeKind::EnumItem => Some(Category::ListItem), NodeKind::EnumNumbering(_) => Some(Category::ListMarker), NodeKind::DescItem => Some(Category::ListItem), - NodeKind::Label(_) => Some(Category::Label), - NodeKind::Ref(_) => Some(Category::Ref), + NodeKind::Math => Some(Category::Math), + NodeKind::Atom(_) => None, + NodeKind::Script => None, + NodeKind::Frac => None, + NodeKind::Align => None, NodeKind::Ident(_) => match parent.kind() { NodeKind::Markup { .. } => Some(Category::Interpolated), NodeKind::Math => Some(Category::Interpolated), NodeKind::FuncCall => Some(Category::Function), NodeKind::MethodCall if i > 0 => Some(Category::Function), - NodeKind::ClosureExpr if i == 0 => Some(Category::Function), - NodeKind::SetExpr => Some(Category::Function), - NodeKind::ShowExpr + NodeKind::Closure if i == 0 => Some(Category::Function), + NodeKind::SetRule => Some(Category::Function), + NodeKind::ShowRule if parent .children() .rev() @@ -336,34 +332,34 @@ impl Category { NodeKind::Str(_) => Some(Category::String), NodeKind::CodeBlock => None, NodeKind::ContentBlock => None, - NodeKind::GroupExpr => None, - NodeKind::ArrayExpr => None, - NodeKind::DictExpr => None, + NodeKind::Parenthesized => None, + NodeKind::Array => None, + NodeKind::Dict => None, NodeKind::Named => None, NodeKind::Keyed => None, - NodeKind::UnaryExpr => None, - NodeKind::BinaryExpr => None, + NodeKind::Unary => None, + NodeKind::Binary => None, NodeKind::FieldAccess => None, NodeKind::FuncCall => None, NodeKind::MethodCall => None, - NodeKind::CallArgs => None, + NodeKind::Args => None, NodeKind::Spread => None, - NodeKind::ClosureExpr => None, - NodeKind::ClosureParams => None, - NodeKind::LetExpr => None, - NodeKind::SetExpr => None, - NodeKind::ShowExpr => None, - NodeKind::WrapExpr => None, - NodeKind::IfExpr => None, - NodeKind::WhileExpr => None, - NodeKind::ForExpr => None, + NodeKind::Closure => None, + NodeKind::Params => None, + NodeKind::LetBinding => None, + NodeKind::SetRule => None, + NodeKind::ShowRule => None, + NodeKind::WrapRule => None, + NodeKind::Conditional => None, + NodeKind::WhileLoop => None, + NodeKind::ForLoop => None, NodeKind::ForPattern => None, - NodeKind::ImportExpr => None, + NodeKind::ModuleImport => None, NodeKind::ImportItems => None, - NodeKind::IncludeExpr => None, - NodeKind::BreakExpr => None, - NodeKind::ContinueExpr => None, - NodeKind::ReturnExpr => None, + NodeKind::ModuleInclude => None, + NodeKind::BreakStmt => None, + NodeKind::ContinueStmt => None, + NodeKind::ReturnStmt => None, NodeKind::Error(_, _) => Some(Category::Error), } @@ -376,15 +372,15 @@ impl Category { Self::Bracket => "punctuation.definition.bracket.typst", Self::Punctuation => "punctuation.typst", Self::Escape => "constant.character.escape.typst", - Self::Shortcut => "constant.character.shortcut.typst", - Self::Quote => "constant.character.quote.typst", + Self::Shorthand => "constant.character.shorthand.typst", + Self::SmartQuote => "constant.character.quote.typst", Self::Strong => "markup.bold.typst", Self::Emph => "markup.italic.typst", Self::Link => "markup.underline.link.typst", Self::Raw => "markup.raw.typst", Self::Math => "string.other.math.typst", Self::MathDelimiter => "punctuation.definition.math.typst", - Self::MathSymbol => "keyword.operator.math.typst", + Self::MathOperator => "keyword.operator.math.typst", Self::Heading => "markup.heading.typst", Self::ListItem => "markup.list.typst", Self::ListMarker => "punctuation.definition.list.typst", diff --git a/src/syntax/kind.rs b/src/syntax/kind.rs index 77d4cd99..3273e72d 100644 --- a/src/syntax/kind.rs +++ b/src/syntax/kind.rs @@ -1,8 +1,7 @@ use std::hash::{Hash, Hasher}; use std::sync::Arc; -use super::ast::{RawNode, Unit}; -use crate::diag::ErrorPos; +use crate::geom::{AngleUnit, LengthUnit}; use crate::util::EcoString; /// All syntactical building blocks that can be part of a Typst document. @@ -11,13 +10,9 @@ use crate::util::EcoString; /// the parser. #[derive(Debug, Clone, PartialEq)] pub enum NodeKind { - /// A line comment, two slashes followed by inner contents, terminated with - /// a newline: `//<str>\n`. + /// A line comment: `// ...`. LineComment, - /// A block comment, a slash and a star followed by inner contents, - /// terminated with a star and a slash: `/*<str>*/`. - /// - /// The comment can contain nested block comments. + /// A block comment: `/* ... */`. BlockComment, /// One or more whitespace characters. Single spaces are collapsed into text /// nodes if they would otherwise be surrounded by text nodes. @@ -43,7 +38,7 @@ pub enum NodeKind { Comma, /// A semicolon terminating an expression: `;`. Semicolon, - /// A colon between name / key and value in a dictionary, argument or + /// A colon between name/key and value in a dictionary, argument or /// parameter list, or between the term and body of a description list /// term: `:`. Colon, @@ -52,22 +47,8 @@ pub enum NodeKind { Star, /// Toggles emphasized text and indicates a subscript in a formula: `_`. Underscore, - /// Starts and ends a math formula. + /// Starts and ends a math formula: `$`. Dollar, - /// A forced line break: `\`. - Backslash, - /// The non-breaking space: `~`. - Tilde, - /// The soft hyphen: `-?`. - HyphQuest, - /// The en-dash: `--`. - Hyph2, - /// The em-dash: `---`. - Hyph3, - /// The ellipsis: `...`. - Dot3, - /// A smart quote: `'` or `"`. - Quote { double: bool }, /// The unary plus, binary addition operator, and start of enum items: `+`. Plus, /// The unary negation, binary subtraction operator, and start of list @@ -160,18 +141,37 @@ pub enum NodeKind { Markup { min_indent: usize }, /// Consecutive text without markup. Text(EcoString), - /// A unicode escape sequence, written as a slash and the letter "u" - /// followed by a hexadecimal unicode entity enclosed in curly braces: - /// `\u{1F5FA}`. + /// A forced line break: `\`. + Linebreak, + /// An escape sequence: `\#`, `\u{1F5FA}`. Escape(char), - /// Strong content: `*Strong*`. + /// A shorthand for a unicode codepoint. For example, `~` for non-breaking + /// space or `-?` for a soft hyphen. + Shorthand(char), + /// A smart quote: `'` or `"`. + SmartQuote { double: bool }, + /// Strong markup: `*Strong*`. Strong, - /// Emphasized content: `_Emphasized_`. + /// Emphasized markup: `_Emphasized_`. Emph, + /// A raw block with optional syntax highlighting: `` `...` ``. + Raw(Arc<RawKind>), /// A hyperlink: `https://typst.org`. Link(EcoString), - /// A raw block with optional syntax highlighting: `` `...` ``. - Raw(Arc<RawNode>), + /// A label: `<label>`. + Label(EcoString), + /// A reference: `@target`. + Ref(EcoString), + /// A section heading: `= Introduction`. + Heading, + /// An item of an unordered list: `- ...`. + ListItem, + /// An item of an enumeration (ordered list): `+ ...` or `1. ...`. + EnumItem, + /// An explicit enumeration numbering: `23.`. + EnumNumbering(usize), + /// An item of a description list: `/ Term: Details. + DescItem, /// A math formula: `$x$`, `$ x^2 $`. Math, /// An atom in a math formula: `x`, `+`, `12`. @@ -182,20 +182,6 @@ pub enum NodeKind { Frac, /// An alignment indicator in a math formula: `&`, `&&`. Align, - /// A section heading: `= Introduction`. - Heading, - /// An item in an unordered list: `- ...`. - ListItem, - /// An item in an enumeration (ordered list): `+ ...` or `1. ...`. - EnumItem, - /// An explicit enumeration numbering: `23.`. - EnumNumbering(usize), - /// An item in a description list: `/ Term: Details. - DescItem, - /// A label: `<label>`. - Label(EcoString), - /// A reference: `@label`. - Ref(EcoString), /// An identifier: `center`. Ident(EcoString), @@ -214,19 +200,19 @@ pub enum NodeKind { /// A content block: `[*Hi* there!]`. ContentBlock, /// A grouped expression: `(1 + 2)`. - GroupExpr, - /// An array expression: `(1, "hi", 12cm)`. - ArrayExpr, - /// A dictionary expression: `(thickness: 3pt, pattern: dashed)`. - DictExpr, + Parenthesized, + /// An array: `(1, "hi", 12cm)`. + Array, + /// A dictionary: `(thickness: 3pt, pattern: dashed)`. + Dict, /// A named pair: `thickness: 3pt`. Named, /// A keyed pair: `"spacy key": true`. Keyed, /// A unary operation: `-x`. - UnaryExpr, + Unary, /// A binary operation: `a + b`. - BinaryExpr, + Binary, /// A field access: `properties.age`. FieldAccess, /// An invocation of a function: `f(x, y)`. @@ -234,50 +220,89 @@ pub enum NodeKind { /// An invocation of a method: `array.push(v)`. MethodCall, /// A function call's argument list: `(x, y)`. - CallArgs, + Args, /// Spreaded arguments or a argument sink: `..x`. Spread, - /// A closure expression: `(x, y) => z`. - ClosureExpr, + /// A closure: `(x, y) => z`. + Closure, /// A closure's parameters: `(x, y)`. - ClosureParams, - /// A let expression: `let x = 1`. - LetExpr, - /// A set expression: `set text(...)`. - SetExpr, - /// A show expression: `show node: heading as [*{nody.body}*]`. - ShowExpr, - /// A wrap expression: `wrap body in columns(2, body)`. - WrapExpr, - /// An if-else expression: `if x { y } else { z }`. - IfExpr, - /// A while loop expression: `while x { ... }`. - WhileExpr, - /// A for loop expression: `for x in y { ... }`. - ForExpr, + Params, + /// A let binding: `let x = 1`. + LetBinding, + /// A set rule: `set text(...)`. + SetRule, + /// A show rule: `show node: heading as [*{nody.body}*]`. + ShowRule, + /// A wrap rule: `wrap body in columns(2, body)`. + WrapRule, + /// An if-else conditional: `if x { y } else { z }`. + Conditional, + /// A while loop: `while x { ... }`. + WhileLoop, + /// A for loop: `for x in y { ... }`. + ForLoop, /// A for loop's destructuring pattern: `x` or `x, y`. ForPattern, - /// An import expression: `import a, b, c from "utils.typ"`. - ImportExpr, - /// Items to import: `a, b, c`. + /// A module import: `import a, b, c from "utils.typ"`. + ModuleImport, + /// Items to import from a module: `a, b, c`. ImportItems, - /// An include expression: `include "chapter1.typ"`. - IncludeExpr, - /// A break expression: `break`. - BreakExpr, - /// A continue expression: `continue`. - ContinueExpr, - /// A return expression: `return x + 1`. - ReturnExpr, + /// A module include: `include "chapter1.typ"`. + ModuleInclude, + /// A break statement: `break`. + BreakStmt, + /// A continue statement: `continue`. + ContinueStmt, + /// A return statement: `return x + 1`. + ReturnStmt, /// An invalid sequence of characters. Error(ErrorPos, EcoString), } +/// Fields of the node kind `Raw`. +#[derive(Debug, Clone, PartialEq, Hash)] +pub struct RawKind { + /// An optional identifier specifying the language to syntax-highlight in. + pub lang: Option<EcoString>, + /// The raw text, determined as the raw string between the backticks trimmed + /// according to the above rules. + pub text: EcoString, + /// Whether the element is block-level, that is, it has 3+ backticks + /// and contains at least one newline. + pub block: bool, +} + +/// Unit of a numeric value. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum Unit { + /// An absolute length unit. + Length(LengthUnit), + /// An angular unit. + Angle(AngleUnit), + /// Font-relative: `1em` is the same as the font size. + Em, + /// Fractions: `fr`. + Fr, + /// Percentage: `%`. + Percent, +} + +/// Where in a node an error should be annotated, +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum ErrorPos { + /// Over the full width of the node. + Full, + /// At the start of the node. + Start, + /// At the end of the node. + End, +} + impl NodeKind { - /// Whether this is a kind of parenthesis. - pub fn is_paren(&self) -> bool { - matches!(self, Self::LeftParen | Self::RightParen) + /// Whether this is trivia. + pub fn is_trivia(&self) -> bool { + self.is_space() || matches!(self, Self::LineComment | Self::BlockComment) } /// Whether this is a space. @@ -285,12 +310,12 @@ impl NodeKind { matches!(self, Self::Space { .. }) } - /// Whether this is trivia. - pub fn is_trivia(&self) -> bool { - self.is_space() || matches!(self, Self::LineComment | Self::BlockComment) + /// Whether this is a left or right parenthesis. + pub fn is_paren(&self) -> bool { + matches!(self, Self::LeftParen | Self::RightParen) } - /// Whether this is a kind of error. + /// Whether this is an error. pub fn is_error(&self) -> bool { matches!(self, NodeKind::Error(_, _)) } @@ -313,14 +338,8 @@ impl NodeKind { Self::Star => "star", Self::Underscore => "underscore", Self::Dollar => "dollar sign", - Self::Backslash => "linebreak", - Self::Tilde => "non-breaking space", - Self::HyphQuest => "soft hyphen", - Self::Hyph2 => "en dash", - Self::Hyph3 => "em dash", - Self::Dot3 => "ellipsis", - Self::Quote { double: false } => "single quote", - Self::Quote { double: true } => "double quote", + Self::SmartQuote { double: false } => "single quote", + Self::SmartQuote { double: true } => "double quote", Self::Plus => "plus", Self::Minus => "minus", Self::Slash => "slash", @@ -363,23 +382,25 @@ impl NodeKind { Self::As => "keyword `as`", Self::Markup { .. } => "markup", Self::Text(_) => "text", + Self::Linebreak => "linebreak", Self::Escape(_) => "escape sequence", + Self::Shorthand(_) => "shorthand", Self::Strong => "strong content", Self::Emph => "emphasized content", - Self::Link(_) => "link", Self::Raw(_) => "raw block", - Self::Math => "math formula", - Self::Atom(_) => "math atom", - Self::Script => "script", - Self::Frac => "fraction", - Self::Align => "alignment indicator", + Self::Link(_) => "link", + Self::Label(_) => "label", + Self::Ref(_) => "reference", Self::Heading => "heading", Self::ListItem => "list item", Self::EnumItem => "enumeration item", Self::EnumNumbering(_) => "enumeration item numbering", Self::DescItem => "description list item", - Self::Label(_) => "label", - Self::Ref(_) => "reference", + Self::Math => "math formula", + Self::Atom(_) => "math atom", + Self::Script => "script", + Self::Frac => "fraction", + Self::Align => "alignment indicator", Self::Ident(_) => "identifier", Self::Bool(_) => "boolean", Self::Int(_) => "integer", @@ -388,34 +409,34 @@ impl NodeKind { Self::Str(_) => "string", Self::CodeBlock => "code block", Self::ContentBlock => "content block", - Self::GroupExpr => "group", - Self::ArrayExpr => "array", - Self::DictExpr => "dictionary", + Self::Parenthesized => "group", + Self::Array => "array", + Self::Dict => "dictionary", Self::Named => "named pair", Self::Keyed => "keyed pair", - Self::UnaryExpr => "unary expression", - Self::BinaryExpr => "binary expression", + Self::Unary => "unary expression", + Self::Binary => "binary expression", Self::FieldAccess => "field access", Self::FuncCall => "function call", Self::MethodCall => "method call", - Self::CallArgs => "call arguments", + Self::Args => "call arguments", Self::Spread => "spread", - Self::ClosureExpr => "closure", - Self::ClosureParams => "closure parameters", - Self::LetExpr => "`let` expression", - Self::SetExpr => "`set` expression", - Self::ShowExpr => "`show` expression", - Self::WrapExpr => "`wrap` expression", - Self::IfExpr => "`if` expression", - Self::WhileExpr => "while-loop expression", - Self::ForExpr => "for-loop expression", + Self::Closure => "closure", + Self::Params => "closure parameters", + Self::LetBinding => "`let` expression", + Self::SetRule => "`set` expression", + Self::ShowRule => "`show` expression", + Self::WrapRule => "`wrap` expression", + Self::Conditional => "`if` expression", + Self::WhileLoop => "while-loop expression", + Self::ForLoop => "for-loop expression", Self::ForPattern => "for-loop destructuring pattern", - Self::ImportExpr => "`import` expression", + Self::ModuleImport => "`import` expression", Self::ImportItems => "import items", - Self::IncludeExpr => "`include` expression", - Self::BreakExpr => "`break` expression", - Self::ContinueExpr => "`continue` expression", - Self::ReturnExpr => "`return` expression", + Self::ModuleInclude => "`include` expression", + Self::BreakStmt => "`break` expression", + Self::ContinueStmt => "`continue` expression", + Self::ReturnStmt => "`return` expression", Self::Error(_, _) => "syntax error", } } @@ -440,13 +461,6 @@ impl Hash for NodeKind { Self::Star => {} Self::Underscore => {} Self::Dollar => {} - Self::Backslash => {} - Self::Tilde => {} - Self::HyphQuest => {} - Self::Hyph2 => {} - Self::Hyph3 => {} - Self::Dot3 => {} - Self::Quote { double } => double.hash(state), Self::Plus => {} Self::Minus => {} Self::Slash => {} @@ -489,23 +503,26 @@ impl Hash for NodeKind { Self::As => {} Self::Markup { min_indent } => min_indent.hash(state), Self::Text(s) => s.hash(state), + Self::Linebreak => {} Self::Escape(c) => c.hash(state), + Self::Shorthand(c) => c.hash(state), + Self::SmartQuote { double } => double.hash(state), Self::Strong => {} Self::Emph => {} - Self::Link(link) => link.hash(state), Self::Raw(raw) => raw.hash(state), - Self::Math => {} - Self::Atom(c) => c.hash(state), - Self::Script => {} - Self::Frac => {} - Self::Align => {} + Self::Link(link) => link.hash(state), + Self::Label(c) => c.hash(state), + Self::Ref(c) => c.hash(state), Self::Heading => {} Self::ListItem => {} Self::EnumItem => {} Self::EnumNumbering(num) => num.hash(state), Self::DescItem => {} - Self::Label(c) => c.hash(state), - Self::Ref(c) => c.hash(state), + Self::Math => {} + Self::Atom(c) => c.hash(state), + Self::Script => {} + Self::Frac => {} + Self::Align => {} Self::Ident(v) => v.hash(state), Self::Bool(v) => v.hash(state), Self::Int(v) => v.hash(state), @@ -514,34 +531,34 @@ impl Hash for NodeKind { Self::Str(v) => v.hash(state), Self::CodeBlock => {} Self::ContentBlock => {} - Self::GroupExpr => {} - Self::ArrayExpr => {} - Self::DictExpr => {} + Self::Parenthesized => {} + Self::Array => {} + Self::Dict => {} Self::Named => {} Self::Keyed => {} - Self::UnaryExpr => {} - Self::BinaryExpr => {} + Self::Unary => {} + Self::Binary => {} Self::FieldAccess => {} Self::FuncCall => {} Self::MethodCall => {} - Self::CallArgs => {} + Self::Args => {} Self::Spread => {} - Self::ClosureExpr => {} - Self::ClosureParams => {} - Self::LetExpr => {} - Self::SetExpr => {} - Self::ShowExpr => {} - Self::WrapExpr => {} - Self::IfExpr => {} - Self::WhileExpr => {} - Self::ForExpr => {} + Self::Closure => {} + Self::Params => {} + Self::LetBinding => {} + Self::SetRule => {} + Self::ShowRule => {} + Self::WrapRule => {} + Self::Conditional => {} + Self::WhileLoop => {} + Self::ForLoop => {} Self::ForPattern => {} - Self::ImportExpr => {} + Self::ModuleImport => {} Self::ImportItems => {} - Self::IncludeExpr => {} - Self::BreakExpr => {} - Self::ContinueExpr => {} - Self::ReturnExpr => {} + Self::ModuleInclude => {} + Self::BreakStmt => {} + Self::ContinueStmt => {} + Self::ReturnStmt => {} Self::Error(pos, msg) => (pos, msg).hash(state), } } |
