Skip to content
This repository was archived by the owner on Feb 22, 2024. It is now read-only.

Play with explicit AST #20

Merged
merged 7 commits into from
Oct 8, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Fix nomenclature
  • Loading branch information
Marko Mikulicic committed Oct 8, 2020
commit 2ec6147d6dc6aebd784d56b4d470d3e3a8fcd5ef
28 changes: 17 additions & 11 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,22 @@ use serde_json::Value;
/// / \
/// ^ \___ Union
/// / \ \
/// / \___ Union \___ [Field("bar")]
/// / \___ Union \___ [Name("bar")]
/// / \
/// ^ \___ [Number(1), Number(2)]
/// ^ \___ [Index(1), Index(2)]
/// / \
/// Root ___/ \___ DotName("foo")
/// ```
///
/// Selectors are left associative, thus `$.foo[1,2]["bar"]` behaves
/// like (pseudocode) `(($.foo)[1,2])["bar"]`; thus the root of the resulting
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth pointing out that the Root selector ($) is not related to the root of the AST? Might confuse people otherwise.

/// tree is actually the right-most selector (the last one to be applied).
///
/// The Path::Root AST node is called "root" because that's the
/// name of the node in the JSONPath grammar. It represents the source of
/// the json value stream which gets operated upon by Selector nodes.
/// This is why despite being called "root", this node doesn't lie at the root
/// of the AST tree.
#[derive(Debug)]
pub enum Path {
Root,
Expand All @@ -43,15 +49,15 @@ pub enum Path {

#[derive(Debug)]
pub enum Selector {
Union(Vec<Index>),
Union(Vec<UnionElement>),
DotName(String),
DotWildcard,
}

#[derive(Debug)]
pub enum Index {
Field(String),
Number(i64),
pub enum UnionElement {
Name(String),
Index(i64),
}

type Iter<'a> = Box<dyn Iterator<Item = &'a Value> + 'a>;
Expand Down Expand Up @@ -79,11 +85,11 @@ impl Selector {
}
}

impl Index {
impl UnionElement {
pub fn get<'a>(&self, v: &'a Value) -> Iter<'a> {
match self {
Index::Field(name) => Box::new(v.get(name).into_iter()),
Index::Number(num) => Box::new(v.get(abs_index(*num, v)).into_iter()),
UnionElement::Name(name) => Box::new(v.get(name).into_iter()),
UnionElement::Index(num) => Box::new(v.get(abs_index(*num, v)).into_iter()),
}
}
}
Expand Down Expand Up @@ -113,9 +119,9 @@ mod test {
let a2 = Path::Sel(Box::new(a1), Selector::DotName("bar".to_owned()));
let a3 = Path::Sel(
Box::new(a2),
Selector::Union(vec![Index::Field("baz".to_owned())]),
Selector::Union(vec![UnionElement::Name("baz".to_owned())]),
);
let a4 = Path::Sel(Box::new(a3), Selector::Union(vec![Index::Number(4)]));
let a4 = Path::Sel(Box::new(a3), Selector::Union(vec![UnionElement::Index(4)]));

let j = json!({"foo":{"bar":{"baz":[10,20,30,40,50,60]}}});
println!("j: {}", j);
Expand Down
4 changes: 2 additions & 2 deletions src/grammar.pest
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
selector = _{ SOI ~ rootSelector ~ jsonPath ~ EOI }
selector = _{ SOI ~ rootSelector ~ matchers ~ EOI }

jsonPath = ${ matcher* }
matchers = ${ matcher* }
rootSelector = { "$" }

matcher = { dotChild | union }
Expand Down
12 changes: 6 additions & 6 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ fn parse_child_name(matcher_rule: pest::iterators::Pair<Rule>) -> String {
}
}

fn parse_union_indices(matcher_rule: pest::iterators::Pair<Rule>) -> Vec<Index> {
fn parse_union_indices(matcher_rule: pest::iterators::Pair<Rule>) -> Vec<UnionElement> {
let mut res = Vec::new();

for r in matcher_rule.into_inner() {
Expand All @@ -58,20 +58,20 @@ fn parse_union_indices(matcher_rule: pest::iterators::Pair<Rule>) -> Vec<Index>
res
}

fn parse_union_child(matcher_rule: pest::iterators::Pair<Rule>) -> Vec<Index> {
fn parse_union_child(matcher_rule: pest::iterators::Pair<Rule>) -> Vec<UnionElement> {
matcher_rule
.into_inner()
.map(|r| match r.as_rule() {
Rule::doubleInner => Index::Field(unescape(r.as_str())),
Rule::singleInner => Index::Field(unescape_single(r.as_str())),
Rule::doubleInner => UnionElement::Name(unescape(r.as_str())),
Rule::singleInner => UnionElement::Name(unescape_single(r.as_str())),
_ => panic!("invalid parse tree {:?}", r),
})
.collect()
}

fn parse_union_array_index(matcher_rule: pest::iterators::Pair<Rule>) -> Index {
fn parse_union_array_index(matcher_rule: pest::iterators::Pair<Rule>) -> UnionElement {
let i = matcher_rule.as_str().parse().unwrap();
Index::Number(i)
UnionElement::Index(i)
}

fn unescape(contents: &str) -> String {
Expand Down