Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The great API simplification #9

Merged
merged 16 commits into from
Jan 8, 2019
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rowan"
version = "0.1.3"
version = "0.2.0"
authors = ["Aleksey Kladov <[email protected]>"]
repository = "https://github.com/matklad/rowan"
license = "MIT OR Apache-2.0"
Expand Down
11 changes: 6 additions & 5 deletions examples/math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ impl rowan::Types for Types {
type RootData = ();
}

type Node<R = rowan::OwnedRoot<Types>> = rowan::SyntaxNode<Types, R>;
type Node = rowan::SyntaxNode<Types>;
type TreePtr<T> = rowan::TreePtr<Types, T>;

struct Parser<I: Iterator<Item = (Token, SmolStr)>> {
builder: GreenNodeBuilder<Types>,
Expand Down Expand Up @@ -98,7 +99,7 @@ impl<I: Iterator<Item = (Token, SmolStr)>> Parser<I> {
fn parse_add(&mut self) {
self.handle_operation(&[Token::Add, Token::Sub], Self::parse_mul)
}
fn parse(mut self) -> Node {
fn parse(mut self) -> TreePtr<Node> {
self.builder.start_internal(NodeType::Marker(ASTKind::Root));
self.parse_add();
self.builder.finish_internal();
Expand All @@ -107,9 +108,9 @@ impl<I: Iterator<Item = (Token, SmolStr)>> Parser<I> {
}
}

fn print<R: rowan::TreeRoot<Types>>(indent: usize, node: Node<R>) {
fn print(indent: usize, node: &Node) {
print!("{:indent$}", "", indent = indent);
if let Some(text) = node.borrowed().leaf_text() {
if let Some(text) = node.leaf_text() {
println!("- {:?} {:?}", text, node.kind());
} else {
println!("- {:?}", node.kind());
Expand Down Expand Up @@ -142,5 +143,5 @@ fn main() {
.peekable(),
}
.parse();
print(0, ast.borrowed());
print(0, &ast);
}
96 changes: 60 additions & 36 deletions examples/s_expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,17 @@ type GreenNodeBuilder = rowan::GreenNodeBuilder<STypes>;
/// SyntaxNode exist in borrowed and owned flavors,
/// which is controlled by the `R` parameter.
#[allow(type_alias_bounds)]
type SyntaxNode<R: rowan::TreeRoot<STypes> = rowan::OwnedRoot<STypes>> =
rowan::SyntaxNode<STypes, R>;
type SyntaxNode = rowan::SyntaxNode<STypes>;

type SyntaxNodeRef<'a> = SyntaxNode<rowan::RefRoot<'a, STypes>>;
type TreePtr<T> = rowan::TreePtr<STypes, T>;

use rowan::TransparentNewType;

/// Now, let's write a parser.
/// Note that `parse` does not return a `Result`:
/// by design, syntax tree can be build even for
/// completely invalid source code.
fn parse(text: &str) -> SyntaxNode {
fn parse(text: &str) -> TreePtr<Root> {
struct Parser {
/// input tokens, including whitespace,
/// in *reverse* order.
Expand All @@ -91,7 +92,7 @@ fn parse(text: &str) -> SyntaxNode {
}

impl Parser {
fn parse(mut self) -> SyntaxNode {
fn parse(mut self) -> TreePtr<Root> {
// Make sure that the root node covers all source
self.builder.start_internal(ROOT);
// Parse a list of S-expressions
Expand All @@ -116,7 +117,8 @@ fn parse(text: &str) -> SyntaxNode {
let green: GreenNode = self.builder.finish();
// Construct a `SyntaxNode` from `GreenNode`,
// using errors as the root data.
SyntaxNode::new(green, self.errors)
let node = SyntaxNode::new(green, self.errors);
Root::cast(&node).unwrap().to_owned()
}
fn list(&mut self) {
// Start the list node
Expand Down Expand Up @@ -223,16 +225,26 @@ fn test_parser() {
/// combination of `serde`, `ron` and `tera` crates invaluable for that!
macro_rules! ast_node {
($ast:ident, $kind:ident) => {
#[derive(Clone, Copy, PartialEq, Eq, Hash)] // note the Copy
struct $ast<'a>(SyntaxNodeRef<'a>);
impl<'a> $ast<'a> {
fn cast(node: SyntaxNodeRef<'a>) -> Option<Self> {
#[derive(PartialEq, Eq, Hash)]
#[repr(transparent)]
struct $ast(SyntaxNode);
unsafe impl TransparentNewType for $ast {
type Repr = SyntaxNode;
}
impl $ast {
#[allow(unused)]
fn cast(node: &SyntaxNode) -> Option<&Self> {
if node.kind() == $kind {
Some($ast(node))
Some(Self::from_repr(node))
} else {
None
}
}
#[allow(unused)]
fn to_owned(&self) -> TreePtr<Self> {
let owned = self.0.to_owned();
TreePtr::cast(owned)
}
}
};
}
Expand All @@ -242,23 +254,36 @@ ast_node!(Atom, ATOM);
ast_node!(List, LIST);

// Sexp is slightly different, so let's do it by hand.
enum Sexp<'a> {
Atom(Atom<'a>),
List(List<'a>),
#[derive(PartialEq, Eq, Hash)]
#[repr(transparent)]
struct Sexp(SyntaxNode);

enum SexpKind<'a> {
Atom(&'a Atom),
List(&'a List),
}

impl<'a> Sexp<'a> {
fn cast(node: SyntaxNodeRef<'a>) -> Option<Self> {
Atom::cast(node)
.map(Sexp::Atom)
.or_else(|| List::cast(node).map(Sexp::List))
impl Sexp {
fn cast(node: &SyntaxNode) -> Option<&Self> {
if Atom::cast(node).is_some() || List::cast(node).is_some() {
Some(unsafe { std::mem::transmute(node) })
} else {
None
}
}

fn kind(&self) -> SexpKind {
Atom::cast(&self.0)
.map(SexpKind::Atom)
.or_else(|| List::cast(&self.0).map(SexpKind::List))
.unwrap()
}
}

// Let's enhance AST nodes with ancillary functions and
// eval.
impl<'a> Root<'a> {
fn sexps(self) -> impl Iterator<Item = Sexp<'a>> {
impl Root {
fn sexps(&self) -> impl Iterator<Item = &Sexp> {
self.0.children().filter_map(Sexp::cast)
}
}
Expand All @@ -270,11 +295,11 @@ enum Op {
Mul,
}

impl<'a> Atom<'a> {
fn eval(self) -> Option<i64> {
impl Atom {
fn eval(&self) -> Option<i64> {
self.0.leaf_text().unwrap().parse().ok()
}
fn as_op(self) -> Option<Op> {
fn as_op(&self) -> Option<Op> {
let text = self.0.leaf_text().unwrap();
let op = match text.as_str() {
"+" => Op::Add,
Expand All @@ -287,13 +312,13 @@ impl<'a> Atom<'a> {
}
}

impl<'a> List<'a> {
fn sexps(self) -> impl Iterator<Item = Sexp<'a>> {
impl List {
fn sexps(&self) -> impl Iterator<Item = &Sexp> {
self.0.children().filter_map(Sexp::cast)
}
fn eval(self) -> Option<i64> {
let op = match self.sexps().nth(0)? {
Sexp::Atom(atom) => atom.as_op()?,
fn eval(&self) -> Option<i64> {
let op = match self.sexps().nth(0)?.kind() {
SexpKind::Atom(atom) => atom.as_op()?,
_ => return None,
};
let arg1 = self.sexps().nth(1)?.eval()?;
Expand All @@ -309,11 +334,11 @@ impl<'a> List<'a> {
}
}

impl<'a> Sexp<'a> {
fn eval(self) -> Option<i64> {
match self {
Sexp::Atom(atom) => atom.eval(),
Sexp::List(list) => list.eval(),
impl Sexp {
fn eval(&self) -> Option<i64> {
match self.kind() {
SexpKind::Atom(atom) => atom.eval(),
SexpKind::List(list) => list.eval(),
}
}
}
Expand All @@ -327,8 +352,7 @@ fn main() {
nan
(+ (* 15 2) 62)
";
let node = parse(sexps);
let root = Root::cast(node.borrowed()).unwrap();
let root = parse(sexps);
let res = root.sexps().map(|it| it.eval()).collect::<Vec<_>>();
eprintln!("{:?}", res);
assert_eq!(res, vec![Some(92), Some(92), None, None, Some(92),])
Expand Down
Loading