Skip to content

Commit f1142df

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

File tree

50 files changed

+2027
-11
lines changed

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
-11
lines changed

partiql-ast/src/pretty.rs

Lines changed: 237 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
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,
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,
5+
pretty_surrounded_doc, PrettyDoc, PRETTY_INDENT_MINOR_NEST,
56
PRETTY_INDENT_SUBORDINATE_CLAUSE_NEST,
67
};
78
use pretty::{DocAllocator, DocBuilder};
9+
use std::borrow::Cow;
810
impl<T> PrettyDoc for AstNode<T>
911
where
1012
T: PrettyDoc,
@@ -316,9 +318,8 @@ impl PrettyDoc for Expr {
316318
Expr::Sexp(inner) => inner.pretty_doc(arena),
317319
Expr::Path(inner) => inner.pretty_doc(arena),
318320
Expr::Call(inner) => inner.pretty_doc(arena),
319-
320321
Expr::CallAgg(inner) => inner.pretty_doc(arena),
321-
322+
Expr::GraphMatch(inner) => inner.pretty_doc(arena),
322323
Expr::Query(inner) => {
323324
let inner = inner.pretty_doc(arena).group();
324325
arena
@@ -329,9 +330,6 @@ impl PrettyDoc for Expr {
329330
Expr::Error => {
330331
unreachable!();
331332
}
332-
Expr::GraphMatch(_inner) => {
333-
todo!("inner.pretty_doc(arena)")
334-
}
335333
}
336334
.group()
337335
}
@@ -1000,6 +998,238 @@ impl PrettyDoc for Join {
1000998
}
1001999
}
10021000

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