Skip to content

Commit b9340a7

Browse files
committed
Add pretty-printing for GPML
1 parent 6194865 commit b9340a7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+2027
-12
lines changed

partiql-ast/src/pretty.rs

Lines changed: 237 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
use crate::ast::*;
22
use partiql_common::pretty::{
3-
pretty_list, pretty_parenthesized_doc, pretty_prefixed_doc, pretty_seperated,
4-
pretty_seperated_doc, pretty_seq, pretty_seq_doc, PrettyDoc, PRETTY_INDENT_MINOR_NEST,
5-
PRETTY_INDENT_SUBORDINATE_CLAUSE_NEST,
3+
pretty_bracketed_doc, pretty_list, pretty_parenthesized_doc, pretty_prefixed_doc,
4+
pretty_seperated, pretty_seperated_doc, pretty_seq, pretty_seq_doc, pretty_surrounded_doc,
5+
PrettyDoc, PRETTY_INDENT_MINOR_NEST, PRETTY_INDENT_SUBORDINATE_CLAUSE_NEST,
66
};
77
use pretty::{DocAllocator, DocBuilder};
8+
use std::borrow::Cow;
89
impl<T> PrettyDoc for AstNode<T>
910
where
1011
T: PrettyDoc,
@@ -316,9 +317,8 @@ impl PrettyDoc for Expr {
316317
Expr::Sexp(inner) => inner.pretty_doc(arena),
317318
Expr::Path(inner) => inner.pretty_doc(arena),
318319
Expr::Call(inner) => inner.pretty_doc(arena),
319-
320320
Expr::CallAgg(inner) => inner.pretty_doc(arena),
321-
321+
Expr::GraphMatch(inner) => inner.pretty_doc(arena),
322322
Expr::Query(inner) => {
323323
let inner = inner.pretty_doc(arena).group();
324324
arena
@@ -329,9 +329,6 @@ impl PrettyDoc for Expr {
329329
Expr::Error => {
330330
unreachable!();
331331
}
332-
Expr::GraphMatch(_inner) => {
333-
todo!("inner.pretty_doc(arena)")
334-
}
335332
}
336333
.group()
337334
}
@@ -1000,6 +997,238 @@ impl PrettyDoc for Join {
1000997
}
1001998
}
1002999

1000+
impl PrettyDoc for GraphMatch {
1001+
fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
1002+
where
1003+
D: DocAllocator<'b, A>,
1004+
D::Doc: Clone,
1005+
A: Clone,
1006+
{
1007+
let head = arena.intersperse(
1008+
[self.expr.pretty_doc(arena), arena.text("MATCH")],
1009+
arena.space(),
1010+
);
1011+
let patterns = self.graph_expr.pretty_doc(arena);
1012+
let match_expr = arena.intersperse([head, patterns], arena.space());
1013+
1014+
let parens_needed = self.graph_expr.node.patterns.len() > 1;
1015+
if parens_needed {
1016+
pretty_parenthesized_doc(match_expr, arena)
1017+
} else {
1018+
match_expr
1019+
}
1020+
}
1021+
}
1022+
1023+
impl PrettyDoc for GraphMatchExpr {
1024+
fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
1025+
where
1026+
D: DocAllocator<'b, A>,
1027+
D::Doc: Clone,
1028+
A: Clone,
1029+
{
1030+
let selector = self.selector.clone().map(|s| {
1031+
let parts: Vec<Cow<'_, str>> = match s {
1032+
GraphMatchSelector::AnyShortest => vec!["ANY".into(), "SHORTEST".into()],
1033+
GraphMatchSelector::AllShortest => vec!["ALL".into(), "SHORTEST".into()],
1034+
GraphMatchSelector::Any => vec!["ANY".into()],
1035+
GraphMatchSelector::AnyK(k) => vec!["ANY".into(), k.to_string().into()],
1036+
GraphMatchSelector::ShortestK(k) => vec!["SHORTEST".into(), k.to_string().into()],
1037+
GraphMatchSelector::ShortestKGroup(k) => {
1038+
vec!["SHORTEST".into(), k.to_string().into(), "GROUP".into()]
1039+
}
1040+
};
1041+
1042+
arena.intersperse(parts, arena.space()).group()
1043+
});
1044+
let patterns = pretty_list(&self.patterns, PRETTY_INDENT_MINOR_NEST, arena);
1045+
if let Some(selector) = selector {
1046+
arena.intersperse([selector, patterns], arena.softline())
1047+
} else {
1048+
patterns
1049+
}
1050+
.group()
1051+
}
1052+
}
1053+
1054+
impl PrettyDoc for GraphMatchPattern {
1055+
fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
1056+
where
1057+
D: DocAllocator<'b, A>,
1058+
D::Doc: Clone,
1059+
A: Clone,
1060+
{
1061+
let pattern = pretty_seperated(
1062+
arena.nil().append(arena.space()),
1063+
&self.parts,
1064+
PRETTY_INDENT_MINOR_NEST,
1065+
arena,
1066+
);
1067+
let mut doc = if let Some(r) = &self.restrictor {
1068+
match r {
1069+
GraphMatchRestrictor::Trail => arena.text("TRAIL"),
1070+
GraphMatchRestrictor::Acyclic => arena.text("ACYCLIC"),
1071+
GraphMatchRestrictor::Simple => arena.text("SIMPLE"),
1072+
}
1073+
.append(arena.space())
1074+
} else {
1075+
arena.nil()
1076+
};
1077+
1078+
let pattern = if let Some(v) = &self.variable {
1079+
arena.intersperse(
1080+
[arena.text(&v.value), arena.text("="), pattern],
1081+
arena.space(),
1082+
)
1083+
} else {
1084+
pattern
1085+
};
1086+
doc = doc.append(pattern);
1087+
1088+
let brackets =
1089+
self.restrictor.is_some() || self.quantifier.is_some() || self.prefilter.is_some();
1090+
1091+
if brackets {
1092+
let doc = if let Some(filter) = &self.prefilter {
1093+
arena.intersperse(
1094+
[doc, arena.text("WHERE"), filter.pretty_doc(arena)],
1095+
arena.space(),
1096+
)
1097+
} else {
1098+
doc
1099+
};
1100+
let bracketed = pretty_bracketed_doc(doc, arena);
1101+
if let Some(postfix) = &self.quantifier {
1102+
arena.concat([bracketed, postfix.pretty_doc(arena)])
1103+
} else {
1104+
bracketed
1105+
}
1106+
} else {
1107+
doc
1108+
}
1109+
.group()
1110+
}
1111+
}
1112+
1113+
impl PrettyDoc for GraphMatchPatternPart {
1114+
fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
1115+
where
1116+
D: DocAllocator<'b, A>,
1117+
D::Doc: Clone,
1118+
A: Clone,
1119+
{
1120+
match self {
1121+
GraphMatchPatternPart::Node(n) => n.pretty_doc(arena),
1122+
GraphMatchPatternPart::Edge(e) => e.pretty_doc(arena),
1123+
GraphMatchPatternPart::Pattern(p) => p.pretty_doc(arena),
1124+
}
1125+
}
1126+
}
1127+
1128+
impl PrettyDoc for GraphMatchNode {
1129+
fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
1130+
where
1131+
D: DocAllocator<'b, A>,
1132+
D::Doc: Clone,
1133+
A: Clone,
1134+
{
1135+
let mut spec = arena.nil();
1136+
if let Some(r) = &self.variable {
1137+
spec = spec.append(arena.text(&r.value));
1138+
}
1139+
if let Some(l) = &self.label {
1140+
debug_assert_eq!(l.len(), 1); // TODO
1141+
spec = spec.append(arena.text(":")).append(arena.text(&l[0].value));
1142+
}
1143+
if let Some(r) = &self.prefilter {
1144+
let parts = [spec, arena.text("WHERE"), r.pretty_doc(arena)];
1145+
spec = arena.intersperse(parts, arena.space()).into();
1146+
}
1147+
pretty_surrounded_doc(spec, "(", ")", arena)
1148+
}
1149+
}
1150+
1151+
impl PrettyDoc for GraphMatchEdge {
1152+
fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
1153+
where
1154+
D: DocAllocator<'b, A>,
1155+
D::Doc: Clone,
1156+
A: Clone,
1157+
{
1158+
let mut spec = None;
1159+
if let Some(r) = &self.variable {
1160+
spec = spec
1161+
.unwrap_or_else(|| arena.nil())
1162+
.append(arena.text(&r.value))
1163+
.into();
1164+
}
1165+
if let Some(l) = &self.label {
1166+
debug_assert_eq!(l.len(), 1); // TODO
1167+
spec = spec
1168+
.unwrap_or_else(|| arena.nil())
1169+
.append(arena.text(":"))
1170+
.append(arena.text(&l[0].value))
1171+
.into();
1172+
}
1173+
if let Some(r) = &self.prefilter {
1174+
let parts = [
1175+
spec.unwrap_or_else(|| arena.nil()),
1176+
arena.text("WHERE"),
1177+
r.pretty_doc(arena),
1178+
];
1179+
spec = arena.intersperse(parts, arena.space()).into();
1180+
}
1181+
1182+
let mut edge = if let Some(spec) = spec {
1183+
let (prefix, suffix) = match self.direction {
1184+
GraphMatchDirection::Right => ("-[", "]->"),
1185+
GraphMatchDirection::Left => ("<-[", "]-"),
1186+
GraphMatchDirection::Undirected => ("~[", "]~"),
1187+
GraphMatchDirection::UndirectedOrRight => ("~[", "]~>"),
1188+
GraphMatchDirection::LeftOrUndirected => ("<~[", "]~"),
1189+
GraphMatchDirection::LeftOrRight => ("<-[", "]->"),
1190+
GraphMatchDirection::LeftOrUndirectedOrRight => ("-[", "]-"),
1191+
};
1192+
pretty_surrounded_doc(spec, prefix, suffix, arena)
1193+
} else {
1194+
let edge = match self.direction {
1195+
GraphMatchDirection::Right => "->",
1196+
GraphMatchDirection::Left => "<-",
1197+
GraphMatchDirection::Undirected => "~",
1198+
GraphMatchDirection::UndirectedOrRight => "~>",
1199+
GraphMatchDirection::LeftOrUndirected => "<~",
1200+
GraphMatchDirection::LeftOrRight => "<->",
1201+
GraphMatchDirection::LeftOrUndirectedOrRight => "-",
1202+
};
1203+
arena.text(edge)
1204+
};
1205+
if let Some(q) = &self.quantifier {
1206+
edge = arena.concat([edge, q.pretty_doc(arena)]);
1207+
}
1208+
edge.group()
1209+
}
1210+
}
1211+
1212+
impl PrettyDoc for GraphMatchQuantifier {
1213+
fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
1214+
where
1215+
D: DocAllocator<'b, A>,
1216+
D::Doc: Clone,
1217+
A: Clone,
1218+
{
1219+
let GraphMatchQuantifier { lower, upper } = &self;
1220+
match (lower, upper) {
1221+
(0, None) => arena.text("*"),
1222+
(1, None) => arena.text("+"),
1223+
(l, u) => {
1224+
let l = Cow::Owned(l.to_string());
1225+
let u = u.map(|u| Cow::Owned(u.to_string())).unwrap_or("".into());
1226+
pretty_surrounded_doc(arena.concat([l, ",".into(), u]), "{", "}", arena)
1227+
}
1228+
}
1229+
}
1230+
}
1231+
10031232
impl PrettyDoc for Let {
10041233
fn pretty_doc<'b, D, A>(&'b self, _arena: &'b D) -> DocBuilder<'b, D, A>
10051234
where

partiql-common/src/pretty.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,28 @@ where
196196
pretty_surrounded_doc(doc, "(", ")", arena)
197197
}
198198

199+
#[inline]
200+
pub fn pretty_sp_bracketed_doc<'b, E, D, A>(doc: E, arena: &'b D) -> DocBuilder<'b, D, A>
201+
where
202+
E: Pretty<'b, D, A>,
203+
D: DocAllocator<'b, A>,
204+
D::Doc: Clone,
205+
A: Clone,
206+
{
207+
pretty_surrounded_doc(doc, "[ ", " ]", arena)
208+
}
209+
210+
#[inline]
211+
pub fn pretty_bracketed_doc<'b, E, D, A>(doc: E, arena: &'b D) -> DocBuilder<'b, D, A>
212+
where
213+
E: Pretty<'b, D, A>,
214+
D: DocAllocator<'b, A>,
215+
D::Doc: Clone,
216+
A: Clone,
217+
{
218+
pretty_surrounded_doc(doc, "[", "]", arena)
219+
}
220+
199221
#[inline]
200222
pub fn pretty_seq_doc<'i, 'b, I, E, D, A>(
201223
seq: I,

partiql-parser/src/parse/partiql.lalrpop

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,8 +1102,8 @@ MatchPatternPartParen: ast::AstNode<ast::GraphMatchPattern> = {
11021102

11031103
//#[inline]
11041104
MatchPatternQuantifier: ast::AstNode<ast::GraphMatchQuantifier> = {
1105-
<lo:@L> "+" <hi:@R> => state.node(ast::GraphMatchQuantifier{ lower:0, upper:None }, lo..hi),
1106-
<lo:@L> "*" <hi:@R> => state.node(ast::GraphMatchQuantifier{ lower:1, upper:None }, lo..hi),
1105+
<lo:@L> "*" <hi:@R> => state.node(ast::GraphMatchQuantifier{ lower:0, upper:None }, lo..hi),
1106+
<lo:@L> "+" <hi:@R> => state.node(ast::GraphMatchQuantifier{ lower:1, upper:None }, lo..hi),
11071107
<lo:@L> "{" <lower:"Int"> "," <upper:"Int"?> "}" <hi:@R> => {
11081108
// TODO error on invalid literal
11091109
state.node(ast::GraphMatchQuantifier{ lower: lower.parse().unwrap(), upper: upper.map(|n| n.parse().unwrap()) }, lo..hi)

partiql/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ partiql-logical-planner = { path = "../partiql-logical-planner" }
3434
partiql-eval = { path = "../partiql-eval" }
3535
partiql-extension-value-functions = { path = "../extension/partiql-extension-value-functions" }
3636
partiql-extension-ion = { path = "../extension/partiql-extension-ion" }
37+
once_cell = "1"
3738

3839

3940
ion-rs_old = { version = "0.18", package = "ion-rs" }

0 commit comments

Comments
 (0)