Skip to content

Commit

Permalink
Refactor: rename DocStorage->Storage, move to own file
Browse files Browse the repository at this point in the history
  • Loading branch information
justinpombrio committed Mar 19, 2024
1 parent 357211f commit 1899a3e
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 96 deletions.
5 changes: 3 additions & 2 deletions src/language/location.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::{DocStorage, Node};
use super::node::Node;
use super::storage::Storage;

/// A location between nodes, or within text, where a cursor could go.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
Expand All @@ -9,7 +10,7 @@ pub enum Location {
}

impl Location {
pub fn cursor_halves(self, s: &DocStorage) -> (Option<Node>, Option<Node>) {
pub fn cursor_halves(self, s: &Storage) -> (Option<Node>, Option<Node>) {
match self {
Location::InText(..) => (None, None),
Location::After(left_sibling) => (Some(left_sibling), left_sibling.next_sibling(s)),
Expand Down
4 changes: 3 additions & 1 deletion src/language/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod indexed_map;
mod language_set;
mod location;
mod node;
mod storage;
mod text;

use partial_pretty_printer as ppp;
Expand All @@ -12,7 +13,8 @@ pub use language_set::{
AritySpec, ConstructSpec, GrammarSpec, LanguageSpec, NotationSetSpec, SortSpec,
};
pub use location::Location;
pub use node::{DocStorage, Node, NodeId};
pub use node::{Node, NodeId};
pub use storage::Storage;

#[derive(thiserror::Error, fmt::Debug)]
pub enum LanguageError {
Expand Down
137 changes: 49 additions & 88 deletions src/language/node.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::forest::{Forest, NodeIndex};
use super::forest;
use super::language_set::{Arity, Construct, Language, LanguageSet, LanguageSpec, NotationSetSpec};
use super::storage::Storage;
use super::text::Text;
use super::LanguageError;
use crate::infra::{bug, SynlessBug};
Expand All @@ -8,25 +9,17 @@ use partial_pretty_printer as ppp;
use std::fmt;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct NodeId(usize);
pub struct NodeId(pub(super) usize);

/// The data stored inside a document node.
struct NodeData {
pub(super) struct NodeData {
id: NodeId,
construct: Construct,
/// Is Some iff the node is texty.
text: Option<Text>,
}

// TODO: Move DocStorage into language_set?
/// Stores all documents and languages.
pub struct DocStorage {
language_set: LanguageSet,
forest: Forest<NodeData>,
next_id: NodeId,
}

/// A node in a document. You'll need a &DocStorage to do anything with it.
/// A node in a document. You'll need a &Storage to do anything with it.
///
/// _Ownership model:_ There is one "primary" Node reference to each tree (anywhere in the tree).
/// When a tree would have two primary references, it's copied instead. When a tree would have
Expand All @@ -35,67 +28,22 @@ pub struct DocStorage {
/// references: they may outlive the primary reference but need to be checked for validity before
/// being used, as the node they reference may have been deleted.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Node(NodeIndex);
pub struct Node(forest::NodeIndex);

/// A long-lived reference to a node that might or might not still exist.
pub struct Bookmark(NodeIndex);

impl DocStorage {
pub fn new() -> DocStorage {
let invalid_dummy_node = {
let mut text = Text::new();
text.set("Dummy node that must never be seen!".to_owned());
NodeData {
id: NodeId(666),
construct: Construct::invalid_dummy(),
text: Some(text),
}
};

DocStorage {
language_set: LanguageSet::new(),
forest: Forest::new(invalid_dummy_node),
next_id: NodeId(0),
}
}

pub fn add_language(&mut self, language_spec: LanguageSpec) -> Result<(), LanguageError> {
self.language_set.add_language(language_spec)
}

pub fn add_notation_set(
&mut self,
language_name: &str,
notation_set: NotationSetSpec,
) -> Result<(), LanguageError> {
self.language_set
.add_notation_set(language_name, notation_set)
}

fn next_id(&mut self) -> NodeId {
let id = self.next_id.0;
self.next_id.0 += 1;
NodeId(id)
}
}

impl Default for DocStorage {
fn default() -> Self {
DocStorage::new()
}
}
pub struct Bookmark(forest::NodeIndex);

impl Node {
/****************
* Constructors *
****************/

pub fn new_hole(s: &mut DocStorage, lang: Language) -> Node {
pub fn new_hole(s: &mut Storage, lang: Language) -> Node {
Node::new(s, lang.hole_construct(&s.language_set))
}

/// Creates a new root node.
pub fn new(s: &mut DocStorage, construct: Construct) -> Node {
pub fn new(s: &mut Storage, construct: Construct) -> Node {
let id = s.next_id();
match construct.arity(&s.language_set) {
Arity::Texty => Node(s.forest.new_node(NodeData {
Expand Down Expand Up @@ -134,33 +82,33 @@ impl Node {
* Node Data *
*************/

pub fn id(self, s: &DocStorage) -> NodeId {
pub fn id(self, s: &Storage) -> NodeId {
s.forest.data(self.0).id
}

pub fn arity(self, s: &DocStorage) -> Arity {
pub fn arity(self, s: &Storage) -> Arity {
s.forest.data(self.0).construct.arity(&s.language_set)
}

/// ("ws" means "whitespace")
pub fn is_comment_or_ws(self, s: &DocStorage) -> bool {
pub fn is_comment_or_ws(self, s: &Storage) -> bool {
s.forest
.data(self.0)
.construct
.is_comment_or_ws(&s.language_set)
}

pub fn notation(self, s: &DocStorage) -> &ValidNotation {
pub fn notation(self, s: &Storage) -> &ValidNotation {
s.forest.data(self.0).construct.notation(&s.language_set)
}

/// Borrow the text of a texty node. `None` if it's not texty.
pub fn text(self, s: &DocStorage) -> Option<&Text> {
pub fn text(self, s: &Storage) -> Option<&Text> {
s.forest.data(self.0).text.as_ref()
}

/// Mutably borrow the text of a texty node. `None` if it's not texty.
pub fn text_mut(self, s: &mut DocStorage) -> Option<&mut Text> {
pub fn text_mut(self, s: &mut Storage) -> Option<&mut Text> {
s.forest.data_mut(self.0).text.as_mut()
}

Expand All @@ -169,12 +117,12 @@ impl Node {
*************/

/// Returns whether this is the root of a tree. Equivalent to `self.parent(s).is_none()`.
pub fn is_at_root(self, s: &DocStorage) -> bool {
pub fn is_at_root(self, s: &Storage) -> bool {
s.forest.parent(self.0).is_none()
}

/// Determine the number of siblings that this node has, including itself.
pub fn num_siblings(&self, s: &DocStorage) -> usize {
pub fn num_siblings(&self, s: &Storage) -> usize {
if let Some(parent) = s.forest.parent(self.0) {
s.forest.num_children(parent)
} else {
Expand All @@ -183,14 +131,14 @@ impl Node {
}

/// Determine this node's index among its siblings. Returns `0` when at the root.
pub fn sibling_index(self, s: &DocStorage) -> usize {
pub fn sibling_index(self, s: &Storage) -> usize {
s.forest.sibling_index(self.0)
}

/// Return the number of children this node has. For a Fixed node, this is
/// its arity. For a Listy node, this is its current number of children.
/// For text, this is None.
pub fn num_children(self, s: &DocStorage) -> Option<usize> {
pub fn num_children(self, s: &Storage) -> Option<usize> {
if s.forest.data(self.0).text.is_some() {
None
} else {
Expand All @@ -202,41 +150,41 @@ impl Node {
* Navigation *
**************/

pub fn parent(self, s: &DocStorage) -> Option<Node> {
pub fn parent(self, s: &Storage) -> Option<Node> {
s.forest.parent(self.0).map(Node)
}

pub fn first_child(self, s: &DocStorage) -> Option<Node> {
pub fn first_child(self, s: &Storage) -> Option<Node> {
s.forest.first_child(self.0).map(Node)
}

pub fn last_child(self, s: &DocStorage) -> Option<Node> {
pub fn last_child(self, s: &Storage) -> Option<Node> {
s.forest
.first_child(self.0)
.map(|n| Node(s.forest.last_sibling(n)))
}

pub fn nth_child(self, s: &DocStorage, n: usize) -> Option<Node> {
pub fn nth_child(self, s: &Storage, n: usize) -> Option<Node> {
s.forest.nth_child(self.0, n).map(Node)
}

pub fn next_sibling(self, s: &DocStorage) -> Option<Node> {
pub fn next_sibling(self, s: &Storage) -> Option<Node> {
s.forest.next(self.0).map(Node)
}

pub fn prev_sibling(self, s: &DocStorage) -> Option<Node> {
pub fn prev_sibling(self, s: &Storage) -> Option<Node> {
s.forest.prev(self.0).map(Node)
}

pub fn first_sibling(self, s: &DocStorage) -> Node {
pub fn first_sibling(self, s: &Storage) -> Node {
Node(s.forest.first_sibling(self.0))
}

pub fn last_sibling(self, s: &DocStorage) -> Node {
pub fn last_sibling(self, s: &Storage) -> Node {
Node(s.forest.last_sibling(self.0))
}

pub fn root(self, s: &DocStorage) -> Node {
pub fn root(self, s: &Storage) -> Node {
Node(s.forest.root(self.0))
}

Expand All @@ -251,7 +199,7 @@ impl Node {
/// created. However, it will return `None` if the bookmark's node
/// has since been deleted, or if it is currently located in a
/// different tree.
pub fn goto_bookmark(self, mark: Bookmark, s: &DocStorage) -> Option<Node> {
pub fn goto_bookmark(self, mark: Bookmark, s: &Storage) -> Option<Node> {
if s.forest.is_valid(mark.0) && s.forest.root(self.0) == s.forest.root(mark.0) {
Some(Node(mark.0))
} else {
Expand All @@ -264,7 +212,7 @@ impl Node {
**************/

/// Check if `other` is allowed where `self` currently is, according to our parent's arity.
fn accepts_replacement(self, s: &DocStorage, other: Node) -> bool {
fn accepts_replacement(self, s: &Storage, other: Node) -> bool {
if let Some(parent) = s.forest.parent(self.0) {
let sort = match Node(parent).arity(s) {
Arity::Fixed(sorts) => sorts.get(&s.language_set, self.sibling_index(s)).bug(),
Expand All @@ -278,7 +226,7 @@ impl Node {
}
}

fn is_listy_and_accepts_child(self, s: &DocStorage, other: Node) -> bool {
fn is_listy_and_accepts_child(self, s: &Storage, other: Node) -> bool {
let other_construct = s.forest.data(other.0).construct;
match self.arity(s) {
Arity::Fixed(_) => false,
Expand All @@ -297,7 +245,7 @@ impl Node {
/// - One node is an ancestor of another (so they would mangle the trees if swapped).
/// - One of the nodes is incompatible with the arity of its new parent.
#[must_use]
pub fn swap(self, s: &mut DocStorage, other: Node) -> bool {
pub fn swap(self, s: &mut Storage, other: Node) -> bool {
if self.accepts_replacement(s, other) && other.accepts_replacement(s, self) {
s.forest.swap(self.0, other.0)
} else {
Expand All @@ -311,7 +259,7 @@ impl Node {
/// - The `new_sibling` is incompatible with the arity of the parent.
/// - The `new_sibling` is not a root.
#[must_use]
pub fn insert_before(self, s: &mut DocStorage, new_sibling: Node) -> bool {
pub fn insert_before(self, s: &mut Storage, new_sibling: Node) -> bool {
if let Some(parent) = self.parent(s) {
if parent.is_listy_and_accepts_child(s, new_sibling) {
s.forest.insert_before(self.0, new_sibling.0)
Expand All @@ -329,7 +277,7 @@ impl Node {
/// - The `new_sibling` is incompatible with the arity of the parent.
/// - The `new_sibling` is not a root.
#[must_use]
pub fn insert_after(self, s: &mut DocStorage, new_sibling: Node) -> bool {
pub fn insert_after(self, s: &mut Storage, new_sibling: Node) -> bool {
if let Some(parent) = self.parent(s) {
if parent.is_listy_and_accepts_child(s, new_sibling) {
s.forest.insert_after(self.0, new_sibling.0)
Expand All @@ -349,7 +297,7 @@ impl Node {
/// - The `new_child` is not a root.
/// - The `new_child` is the root of `self`.
#[must_use]
pub fn insert_last_child(self, s: &mut DocStorage, new_child: Node) -> bool {
pub fn insert_last_child(self, s: &mut Storage, new_child: Node) -> bool {
if self.is_listy_and_accepts_child(s, new_child) {
s.forest.insert_last_child(self.0, new_child.0)
} else {
Expand All @@ -363,7 +311,7 @@ impl Node {
/// - The parent is not listy.
/// - `self` is a root.
#[must_use]
pub fn detach(self, s: &mut DocStorage) -> bool {
pub fn detach(self, s: &mut Storage) -> bool {
if let Some(parent) = self.parent(s) {
match parent.arity(s) {
Arity::Fixed(_) => false,
Expand All @@ -378,3 +326,16 @@ impl Node {
}
}
}

impl NodeData {
/// Must never use this node!
pub(super) fn invalid_dummy() -> NodeData {
let mut text = Text::new();
text.set("Dummy node that must never be seen!".to_owned());
NodeData {
id: NodeId(666),
construct: Construct::invalid_dummy(),
text: Some(text),
}
}
}
Loading

0 comments on commit 1899a3e

Please sign in to comment.