mirror of
https://github.com/typst/typst
synced 2025-05-13 12:36:23 +08:00
Impl Eq
for syntax tree types
This commit is contained in:
parent
80e73979f3
commit
56b6a2a908
@ -29,7 +29,7 @@ pub trait AstNode: Sized {
|
|||||||
|
|
||||||
macro_rules! node {
|
macro_rules! node {
|
||||||
($(#[$attr:meta])* $name:ident) => {
|
($(#[$attr:meta])* $name:ident) => {
|
||||||
#[derive(Debug, Default, Clone, PartialEq, Hash)]
|
#[derive(Debug, Default, Clone, Hash)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
$(#[$attr])*
|
$(#[$attr])*
|
||||||
pub struct $name(SyntaxNode);
|
pub struct $name(SyntaxNode);
|
||||||
@ -73,7 +73,7 @@ impl Markup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// An expression in markup, math or code.
|
/// An expression in markup, math or code.
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
/// Plain text without markup.
|
/// Plain text without markup.
|
||||||
Text(Text),
|
Text(Text),
|
||||||
@ -1055,7 +1055,7 @@ impl Array {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// An item in an array.
|
/// An item in an array.
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
pub enum ArrayItem {
|
pub enum ArrayItem {
|
||||||
/// A bare expression: `12`.
|
/// A bare expression: `12`.
|
||||||
Pos(Expr),
|
Pos(Expr),
|
||||||
@ -1092,7 +1092,7 @@ impl Dict {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// An item in an dictionary expresssion.
|
/// An item in an dictionary expresssion.
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
pub enum DictItem {
|
pub enum DictItem {
|
||||||
/// A named pair: `thickness: 3pt`.
|
/// A named pair: `thickness: 3pt`.
|
||||||
Named(Named),
|
Named(Named),
|
||||||
@ -1452,7 +1452,7 @@ impl Args {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// An argument to a function call.
|
/// An argument to a function call.
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
pub enum Arg {
|
pub enum Arg {
|
||||||
/// A positional argument: `12`.
|
/// A positional argument: `12`.
|
||||||
Pos(Expr),
|
Pos(Expr),
|
||||||
@ -1509,7 +1509,7 @@ impl Closure {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A parameter to a closure.
|
/// A parameter to a closure.
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
pub enum Param {
|
pub enum Param {
|
||||||
/// A positional parameter: `x`.
|
/// A positional parameter: `x`.
|
||||||
Pos(Ident),
|
Pos(Ident),
|
||||||
@ -1724,7 +1724,7 @@ impl ModuleImport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The items that ought to be imported from a file.
|
/// The items that ought to be imported from a file.
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
pub enum Imports {
|
pub enum Imports {
|
||||||
/// All items in the scope of the file should be imported.
|
/// All items in the scope of the file should be imported.
|
||||||
Wildcard,
|
Wildcard,
|
||||||
|
@ -9,11 +9,11 @@ use crate::diag::SourceError;
|
|||||||
use crate::util::EcoString;
|
use crate::util::EcoString;
|
||||||
|
|
||||||
/// A node in the untyped syntax tree.
|
/// A node in the untyped syntax tree.
|
||||||
#[derive(Clone, PartialEq, Hash)]
|
#[derive(Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct SyntaxNode(Repr);
|
pub struct SyntaxNode(Repr);
|
||||||
|
|
||||||
/// The three internal representations.
|
/// The three internal representations.
|
||||||
#[derive(Clone, PartialEq, Hash)]
|
#[derive(Clone, Eq, PartialEq, Hash)]
|
||||||
enum Repr {
|
enum Repr {
|
||||||
/// A leaf node.
|
/// A leaf node.
|
||||||
Leaf(LeafNode),
|
Leaf(LeafNode),
|
||||||
@ -147,6 +147,15 @@ impl SyntaxNode {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set a synthetic span for the node and all its descendants.
|
||||||
|
pub fn synthesize(&mut self, span: Span) {
|
||||||
|
match &mut self.0 {
|
||||||
|
Repr::Leaf(leaf) => leaf.span = span,
|
||||||
|
Repr::Inner(inner) => Arc::make_mut(inner).synthesize(span),
|
||||||
|
Repr::Error(error) => Arc::make_mut(error).span = span,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SyntaxNode {
|
impl SyntaxNode {
|
||||||
@ -174,15 +183,6 @@ impl SyntaxNode {
|
|||||||
*self = SyntaxNode::error(message, text, ErrorPos::Full);
|
*self = SyntaxNode::error(message, text, ErrorPos::Full);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a synthetic span for the node and all its descendants.
|
|
||||||
pub(crate) fn synthesize(&mut self, span: Span) {
|
|
||||||
match &mut self.0 {
|
|
||||||
Repr::Leaf(leaf) => leaf.span = span,
|
|
||||||
Repr::Inner(inner) => Arc::make_mut(inner).synthesize(span),
|
|
||||||
Repr::Error(error) => Arc::make_mut(error).span = span,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Assign spans to each node.
|
/// Assign spans to each node.
|
||||||
pub(super) fn numberize(
|
pub(super) fn numberize(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -212,7 +212,7 @@ impl SyntaxNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Whether this is a leaf node.
|
/// Whether this is a leaf node.
|
||||||
pub(crate) fn is_leaf(&self) -> bool {
|
pub(super) fn is_leaf(&self) -> bool {
|
||||||
matches!(self.0, Repr::Leaf(_))
|
matches!(self.0, Repr::Leaf(_))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,7 +291,7 @@ impl Default for SyntaxNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A leaf node in the untyped syntax tree.
|
/// A leaf node in the untyped syntax tree.
|
||||||
#[derive(Clone, Hash)]
|
#[derive(Clone, Eq, PartialEq, Hash)]
|
||||||
struct LeafNode {
|
struct LeafNode {
|
||||||
/// What kind of node this is (each kind would have its own struct in a
|
/// What kind of node this is (each kind would have its own struct in a
|
||||||
/// strongly typed AST).
|
/// strongly typed AST).
|
||||||
@ -322,14 +322,8 @@ impl Debug for LeafNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for LeafNode {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.kind == other.kind && self.text == other.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An inner node in the untyped syntax tree.
|
/// An inner node in the untyped syntax tree.
|
||||||
#[derive(Clone, Hash)]
|
#[derive(Clone, Eq, PartialEq, Hash)]
|
||||||
struct InnerNode {
|
struct InnerNode {
|
||||||
/// What kind of node this is (each kind would have its own struct in a
|
/// What kind of node this is (each kind would have its own struct in a
|
||||||
/// strongly typed AST).
|
/// strongly typed AST).
|
||||||
@ -378,6 +372,7 @@ impl InnerNode {
|
|||||||
/// Set a synthetic span for the node and all its descendants.
|
/// Set a synthetic span for the node and all its descendants.
|
||||||
fn synthesize(&mut self, span: Span) {
|
fn synthesize(&mut self, span: Span) {
|
||||||
self.span = span;
|
self.span = span;
|
||||||
|
self.upper = span.number();
|
||||||
for child in &mut self.children {
|
for child in &mut self.children {
|
||||||
child.synthesize(span);
|
child.synthesize(span);
|
||||||
}
|
}
|
||||||
@ -573,18 +568,8 @@ impl Debug for InnerNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for InnerNode {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.kind == other.kind
|
|
||||||
&& self.len == other.len
|
|
||||||
&& self.descendants == other.descendants
|
|
||||||
&& self.erroneous == other.erroneous
|
|
||||||
&& self.children == other.children
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An error node in the untyped syntax tree.
|
/// An error node in the untyped syntax tree.
|
||||||
#[derive(Clone, Hash)]
|
#[derive(Clone, Eq, PartialEq, Hash)]
|
||||||
struct ErrorNode {
|
struct ErrorNode {
|
||||||
/// The error message.
|
/// The error message.
|
||||||
message: EcoString,
|
message: EcoString,
|
||||||
@ -623,12 +608,6 @@ impl Debug for ErrorNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for ErrorNode {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.message == other.message && self.text == other.text && self.pos == other.pos
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Where in a node an error should be annotated,
|
/// Where in a node an error should be annotated,
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
pub enum ErrorPos {
|
pub enum ErrorPos {
|
||||||
|
@ -213,16 +213,18 @@ fn next_nesting(node: &SyntaxNode, nesting: &mut usize) {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use super::super::{parse, Source};
|
use super::super::{parse, Source, Span};
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn test(prev: &str, range: Range<usize>, with: &str, incremental: bool) {
|
fn test(prev: &str, range: Range<usize>, with: &str, incremental: bool) {
|
||||||
let mut source = Source::detached(prev);
|
let mut source = Source::detached(prev);
|
||||||
let prev = source.root().clone();
|
let prev = source.root().clone();
|
||||||
let range = source.edit(range, with);
|
let range = source.edit(range, with);
|
||||||
let found = source.root();
|
let mut found = source.root().clone();
|
||||||
let expected = parse(source.text());
|
let mut expected = parse(source.text());
|
||||||
if found != &expected {
|
found.synthesize(Span::detached());
|
||||||
|
expected.synthesize(Span::detached());
|
||||||
|
if found != expected {
|
||||||
eprintln!("source: {:?}", source.text());
|
eprintln!("source: {:?}", source.text());
|
||||||
eprintln!("previous: {prev:#?}");
|
eprintln!("previous: {prev:#?}");
|
||||||
eprintln!("expected: {expected:#?}");
|
eprintln!("expected: {expected:#?}");
|
||||||
|
@ -406,6 +406,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_source_file_edit() {
|
fn test_source_file_edit() {
|
||||||
|
// This tests only the non-parser parts. The reparsing itself is
|
||||||
|
// tested separately.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn test(prev: &str, range: Range<usize>, with: &str, after: &str) {
|
fn test(prev: &str, range: Range<usize>, with: &str, after: &str) {
|
||||||
let mut source = Source::detached(prev);
|
let mut source = Source::detached(prev);
|
||||||
@ -413,7 +415,6 @@ mod tests {
|
|||||||
source.edit(range, with);
|
source.edit(range, with);
|
||||||
assert_eq!(source.text, result.text);
|
assert_eq!(source.text, result.text);
|
||||||
assert_eq!(source.lines, result.lines);
|
assert_eq!(source.lines, result.lines);
|
||||||
assert_eq!(*source.root, *result.root);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test inserting at the begining.
|
// Test inserting at the begining.
|
||||||
|
@ -16,7 +16,7 @@ use typst::doc::{Document, Element, Frame, Meta};
|
|||||||
use typst::font::{Font, FontBook};
|
use typst::font::{Font, FontBook};
|
||||||
use typst::geom::{Abs, RgbaColor, Sides, Smart};
|
use typst::geom::{Abs, RgbaColor, Sides, Smart};
|
||||||
use typst::model::{func, Library, Value};
|
use typst::model::{func, Library, Value};
|
||||||
use typst::syntax::{Source, SourceId, SyntaxNode};
|
use typst::syntax::{Source, SourceId, Span, SyntaxNode};
|
||||||
use typst::util::{Buffer, PathExt};
|
use typst::util::{Buffer, PathExt};
|
||||||
use typst::World;
|
use typst::World;
|
||||||
use typst_library::layout::PageNode;
|
use typst_library::layout::PageNode;
|
||||||
@ -591,11 +591,21 @@ fn test_reparse(text: &str, i: usize, rng: &mut LinearShift) -> bool {
|
|||||||
incr_source.edit(replace.clone(), with);
|
incr_source.edit(replace.clone(), with);
|
||||||
|
|
||||||
let edited_src = incr_source.text();
|
let edited_src = incr_source.text();
|
||||||
let incr_root = incr_source.root();
|
|
||||||
let ref_source = Source::detached(edited_src);
|
let ref_source = Source::detached(edited_src);
|
||||||
let ref_root = ref_source.root();
|
let mut ref_root = ref_source.root().clone();
|
||||||
let mut ok = incr_root == ref_root;
|
let mut incr_root = incr_source.root().clone();
|
||||||
if !ok {
|
|
||||||
|
// Ensures that the span numbering invariants hold.
|
||||||
|
let spans_ok = test_spans(&ref_root) && test_spans(&incr_root);
|
||||||
|
|
||||||
|
// Remove all spans so that the comparison works out.
|
||||||
|
let tree_ok = {
|
||||||
|
ref_root.synthesize(Span::detached());
|
||||||
|
incr_root.synthesize(Span::detached());
|
||||||
|
ref_root == incr_root
|
||||||
|
};
|
||||||
|
|
||||||
|
if !tree_ok {
|
||||||
println!(
|
println!(
|
||||||
" Subtest {i} reparse differs from clean parse when inserting '{with}' at {}-{} ❌\n",
|
" Subtest {i} reparse differs from clean parse when inserting '{with}' at {}-{} ❌\n",
|
||||||
replace.start, replace.end,
|
replace.start, replace.end,
|
||||||
@ -605,9 +615,7 @@ fn test_reparse(text: &str, i: usize, rng: &mut LinearShift) -> bool {
|
|||||||
println!(" Full source ({}):\n\"{edited_src:?}\"", edited_src.len());
|
println!(" Full source ({}):\n\"{edited_src:?}\"", edited_src.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
ok &= test_spans(ref_root);
|
spans_ok && tree_ok
|
||||||
ok &= test_spans(incr_root);
|
|
||||||
ok
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut pick = |range: Range<usize>| {
|
let mut pick = |range: Range<usize>| {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user