Skip to content

Commit

Permalink
Add Text (for Ast), and some of AstRef
Browse files Browse the repository at this point in the history
  • Loading branch information
justinpombrio committed Mar 12, 2024
1 parent ca3b3fb commit fc45285
Show file tree
Hide file tree
Showing 5 changed files with 331 additions and 7 deletions.
121 changes: 121 additions & 0 deletions src/language/ast.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
use super::forest::{Forest, NodeIndex};
use super::language_set::{Construct, DocCondition, LanguageSet, StyleLabel, ValidNotation};
use super::text::Text;
use crate::infra::SynlessBug;
use partial_pretty_printer as ppp;
use std::fmt;

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

struct AstNode {
id: AstId,
construct: Construct,
text: Option<Text>,
}

struct DocStorage {
language_set: LanguageSet,
forest: Forest<AstNode>,
}

/********************************************
* AstRef: implements PrettyDoc *
********************************************/

// TODO: These will need more data, and should be moved somewhere.
type Style = ();

#[derive(Clone, Copy)]
struct AstRef<'d> {
storage: &'d DocStorage,
node_index: NodeIndex,
}

impl<'d> AstRef<'d> {
fn node(self) -> &'d AstNode {
self.storage.forest.data(self.node_index)
}
}

impl<'d> ppp::PrettyDoc<'d> for AstRef<'d> {
type Id = AstId;
type Style = Style;
type StyleLabel = StyleLabel;
type Condition = DocCondition;

fn id(self) -> AstId {
self.node().id
}

fn notation(self) -> &'d ValidNotation {
self.node().construct.notation(&self.storage.language_set)
}

fn condition(self, condition: &DocCondition) -> bool {
// TODO
false
}

fn lookup_style(self, style_label: StyleLabel) -> Style {
// TODO
()

Check failure on line 62 in src/language/ast.rs

View workflow job for this annotation

GitHub Actions / build

unneeded unit expression
}

fn node_style(self) -> Style {
// TODO
()

Check failure on line 67 in src/language/ast.rs

View workflow job for this annotation

GitHub Actions / build

unneeded unit expression
}

fn num_children(self) -> Option<usize> {
if self.node().text.is_some() {
None
} else {
Some(self.storage.forest.num_children(self.node_index))
}
}

fn unwrap_text(self) -> &'d str {
self.node().text.as_ref().bug().as_str()
}

fn unwrap_child(self, i: usize) -> AstRef<'d> {
let mut child = self.storage.forest.first_child(self.node_index).bug();
for _ in 0..i {
child = self.storage.forest.next(child).bug();
}
AstRef {
storage: self.storage,
node_index: child,
}
}

fn unwrap_last_child(self) -> AstRef<'d> {
let first_child = self.storage.forest.first_child(self.node_index).bug();
let last_child = self.storage.forest.last_sibling(first_child);
AstRef {
storage: self.storage,
node_index: last_child,
}
}

fn unwrap_prev_sibling(self, _: Self, _: usize) -> AstRef<'d> {
AstRef {
storage: self.storage,
node_index: self.storage.forest.prev(self.node_index).bug(),
}
}
}

impl<'d> fmt::Debug for AstRef<'d> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "AstRef({:?})", self.node_index)
}
}

// Ast methods:
// - navigation, bookmarks
// - editing: text, children
// - grammar: get construct, arity
// - construction: hole, text, branch
// - PrettyDoc: get construct, notation
48 changes: 48 additions & 0 deletions src/language/forest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,24 @@ impl<D> Forest<D> {
}
}

/// Get the `node`'s leftmost sibling (which could be itself).
pub fn first_sibling(&self, node: NodeIndex) -> NodeIndex {
if let Some(parent) = self.arena[node].parent {
self.arena[parent].child.bug()
} else {
node
}
}

/// Get the `node`'s rightmost sibling (which could be itself).
pub fn last_sibling(&self, node: NodeIndex) -> NodeIndex {
if let Some(parent) = self.arena[node].parent {
self.arena[self.arena[parent].child.bug()].prev
} else {
node
}
}

/// Whether this node is first among its siblings. (True if there's one sibling.)
pub fn is_first(&self, node: NodeIndex) -> bool {
if let Some(parent) = self.arena[node].parent {
Expand All @@ -126,6 +144,20 @@ impl<D> Forest<D> {
}
}

pub fn num_children(&self, node: NodeIndex) -> usize {
if let Some(child) = self.arena[node].child {
let mut num_children = 1;
let mut other_child = self.arena[child].next;
while other_child != child {
num_children += 1;
other_child = self.arena[other_child].next;
}
num_children
} else {
0
}
}

/// Borrows the data stored inside `node`.
pub fn data(&self, node: NodeIndex) -> &D {
&self.arena[node].data
Expand Down Expand Up @@ -469,6 +501,7 @@ mod forest_tests {
self.display
.push_str(&format!("{}", self.forest.data(node)));
self.node_count += 1;
let mut num_children = 0;
if let Some(first_child) = self.forest.first_child(node) {
let mut child = first_child;
assert!(self.forest.is_first(child));
Expand All @@ -478,12 +511,14 @@ mod forest_tests {
loop {
self.display.push(' ');
self.verify_tree(child, Some(node), expected_root);
num_children += 1;
match self.forest.next(child) {
None => break,
Some(c) => child = c,
}
}
}
assert_eq!(self.forest.num_children(node), num_children);
self.display.push(')');
}
}
Expand Down Expand Up @@ -531,6 +566,19 @@ mod forest_tests {
);
}

#[test]
fn test_siblings() {
let mut forest = Forest::new("");
let parent = make_sisters(&mut forest);
let elder = forest.first_child(parent).unwrap();
let younger = forest.next(elder).unwrap();

assert_eq!(forest.first_sibling(younger), elder);
assert_eq!(forest.first_sibling(elder), elder);
assert_eq!(forest.last_sibling(younger), younger);
assert_eq!(forest.last_sibling(elder), younger);
}

#[test]
fn test_swap() {
let mut forest = Forest::new("");
Expand Down
34 changes: 27 additions & 7 deletions src/language/language_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,10 @@ struct LanguageCompiled {
grammar: GrammarCompiled,
notation_sets_by_name: HashMap<String, NotationSetId>,
current_notation_set: NotationSetId,
/// NotationSetId -> NotationSet
notation_sets: Vec<NotationSet>,
/// NotationSetId -> NotationSetCompiled
notation_sets: Vec<NotationSetCompiled>,
}

// TODO: These will need more data.
type StyleLabel = u32;
type DocCondition = ();
type ValidNotation = ppp::ValidNotation<StyleLabel, DocCondition>;

struct NotationSetCompiled {
/// ConstructId -> ValidNotation
notations: Vec<ValidNotation>,
Expand All @@ -110,6 +105,11 @@ struct NotationSetCompiled {
* Public Interface *
********************************************/

// TODO: These will need more data, and should be moved somewhere.
pub type StyleLabel = u32;
pub type DocCondition = ();
pub type ValidNotation = ppp::ValidNotation<StyleLabel, DocCondition>;

/// The (unique) collection of all loaded [`Language`]s.
pub struct LanguageSet {
languages_by_name: HashMap<String, LanguageId>,
Expand Down Expand Up @@ -210,6 +210,22 @@ impl Language {
notation_set: *id,
})
}

pub fn current_notation_set(self, l: &LanguageSet) -> NotationSet {
NotationSet {
language: self.language,
notation_set: l.languages[self.language].current_notation_set,
}
}
}

impl NotationSet {
pub fn notation(self, l: &LanguageSet, construct: Construct) -> &ValidNotation {
if self.language != construct.language {
bug!("NotationSet::notation - language mismatch");
}
&l.languages[self.language].notation_sets[self.notation_set].notations[construct.construct]
}
}

impl Sort {
Expand Down Expand Up @@ -268,6 +284,10 @@ impl Construct {
}),
}
}

pub fn notation(self, l: &LanguageSet) -> &ValidNotation {
self.language().current_notation_set(l).notation(l, self)
}
}

impl FixedSorts {
Expand Down
2 changes: 2 additions & 0 deletions src/language/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
mod ast;
mod forest;
mod language_set;
mod text;

use std::fmt;

Expand Down
Loading

0 comments on commit fc45285

Please sign in to comment.