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

refactor: remove arbitrary indirections #5122

Merged
merged 2 commits into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 2 additions & 2 deletions prqlc/bindings/prqlc-python/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,15 +232,15 @@ mod test {
fn debug_prql_lineage() {
assert_snapshot!(
debug::prql_lineage(r#"from a | select { beta, gamma }"#).unwrap(),
@r#"{"frames":[["1:9-31",{"columns":[{"Single":{"name":["a","beta"],"target_id":117,"target_name":null}},{"Single":{"name":["a","gamma"],"target_id":118,"target_name":null}}],"inputs":[{"id":115,"name":"a","table":["default_db","a"]}]}]],"nodes":[{"id":115,"kind":"Ident","span":"1:0-6","ident":{"Ident":["default_db","a"]},"parent":120},{"id":117,"kind":"Ident","span":"1:18-22","ident":{"Ident":["this","a","beta"]},"targets":[115],"parent":119},{"id":118,"kind":"Ident","span":"1:24-29","ident":{"Ident":["this","a","gamma"]},"targets":[115],"parent":119},{"id":119,"kind":"Tuple","span":"1:16-31","children":[117,118],"parent":120},{"id":120,"kind":"TransformCall: Select","span":"1:9-31","children":[115,119]}],"ast":{"name":"Project","stmts":[{"VarDef":{"kind":"Main","name":"main","value":{"Pipeline":{"exprs":[{"FuncCall":{"name":{"Ident":"from","span":"1:0-4"},"args":[{"Ident":"a","span":"1:5-6"}]},"span":"1:0-6"},{"FuncCall":{"name":{"Ident":"select","span":"1:9-15"},"args":[{"Tuple":[{"Ident":"beta","span":"1:18-22"},{"Ident":"gamma","span":"1:24-29"}],"span":"1:16-31"}]},"span":"1:9-31"}]},"span":"1:0-31"}},"span":"1:0-31"}]}}"#
@r#"{"frames":[["1:9-31",{"columns":[{"Single":{"name":["a","beta"],"target_id":117,"target_name":null}},{"Single":{"name":["a","gamma"],"target_id":118,"target_name":null}}],"inputs":[{"id":115,"name":"a","table":["default_db","a"]}]}]],"nodes":[{"id":115,"kind":"Ident","span":"1:0-6","ident":{"Ident":["default_db","a"]},"parent":120},{"id":117,"kind":"Ident","span":"1:18-22","ident":{"Ident":["this","a","beta"]},"targets":[115],"parent":119},{"id":118,"kind":"Ident","span":"1:24-29","ident":{"Ident":["this","a","gamma"]},"targets":[115],"parent":119},{"id":119,"kind":"Tuple","span":"1:16-31","children":[117,118],"parent":120},{"id":120,"kind":"TransformCall: Select","span":"1:9-31","children":[115,119]}],"ast":{"name":"Project","stmts":[{"VarDef":{"kind":"Main","name":"main","value":{"Pipeline":{"exprs":[{"FuncCall":{"name":{"Ident":["from"],"span":"1:0-4"},"args":[{"Ident":["a"],"span":"1:5-6"}]},"span":"1:0-6"},{"FuncCall":{"name":{"Ident":["select"],"span":"1:9-15"},"args":[{"Tuple":[{"Ident":["beta"],"span":"1:18-22"},{"Ident":["gamma"],"span":"1:24-29"}],"span":"1:16-31"}]},"span":"1:9-31"}]},"span":"1:0-31"}},"span":"1:0-31"}]}}"#
);
}

#[test]
fn debug_pl_to_lineage() {
assert_snapshot!(
prql_to_pl(r#"from a | select { beta, gamma }"#).and_then(|x| debug::pl_to_lineage(&x)).unwrap(),
@r#"{"frames":[["1:9-31",{"columns":[{"Single":{"name":["a","beta"],"target_id":117,"target_name":null}},{"Single":{"name":["a","gamma"],"target_id":118,"target_name":null}}],"inputs":[{"id":115,"name":"a","table":["default_db","a"]}]}]],"nodes":[{"id":115,"kind":"Ident","span":"1:0-6","ident":{"Ident":["default_db","a"]},"parent":120},{"id":117,"kind":"Ident","span":"1:18-22","ident":{"Ident":["this","a","beta"]},"targets":[115],"parent":119},{"id":118,"kind":"Ident","span":"1:24-29","ident":{"Ident":["this","a","gamma"]},"targets":[115],"parent":119},{"id":119,"kind":"Tuple","span":"1:16-31","children":[117,118],"parent":120},{"id":120,"kind":"TransformCall: Select","span":"1:9-31","children":[115,119]}],"ast":{"name":"Project","stmts":[{"VarDef":{"kind":"Main","name":"main","value":{"Pipeline":{"exprs":[{"FuncCall":{"name":{"Ident":"from","span":"1:0-4"},"args":[{"Ident":"a","span":"1:5-6"}]},"span":"1:0-6"},{"FuncCall":{"name":{"Ident":"select","span":"1:9-15"},"args":[{"Tuple":[{"Ident":"beta","span":"1:18-22"},{"Ident":"gamma","span":"1:24-29"}],"span":"1:16-31"}]},"span":"1:9-31"}]},"span":"1:0-31"}},"span":"1:0-31"}]}}"#
@r#"{"frames":[["1:9-31",{"columns":[{"Single":{"name":["a","beta"],"target_id":117,"target_name":null}},{"Single":{"name":["a","gamma"],"target_id":118,"target_name":null}}],"inputs":[{"id":115,"name":"a","table":["default_db","a"]}]}]],"nodes":[{"id":115,"kind":"Ident","span":"1:0-6","ident":{"Ident":["default_db","a"]},"parent":120},{"id":117,"kind":"Ident","span":"1:18-22","ident":{"Ident":["this","a","beta"]},"targets":[115],"parent":119},{"id":118,"kind":"Ident","span":"1:24-29","ident":{"Ident":["this","a","gamma"]},"targets":[115],"parent":119},{"id":119,"kind":"Tuple","span":"1:16-31","children":[117,118],"parent":120},{"id":120,"kind":"TransformCall: Select","span":"1:9-31","children":[115,119]}],"ast":{"name":"Project","stmts":[{"VarDef":{"kind":"Main","name":"main","value":{"Pipeline":{"exprs":[{"FuncCall":{"name":{"Ident":["from"],"span":"1:0-4"},"args":[{"Ident":["a"],"span":"1:5-6"}]},"span":"1:0-6"},{"FuncCall":{"name":{"Ident":["select"],"span":"1:9-15"},"args":[{"Tuple":[{"Ident":["beta"],"span":"1:18-22"},{"Ident":["gamma"],"span":"1:24-29"}],"span":"1:16-31"}]},"span":"1:9-31"}]},"span":"1:0-31"}},"span":"1:0-31"}]}}"#
);
}
}
132 changes: 62 additions & 70 deletions prqlc/prqlc-parser/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub(crate) fn expr() -> impl Parser<TokenKind, Expr, Error = PError> + Clone {
recursive(|expr| {
let literal = select! { TokenKind::Literal(lit) => ExprKind::Literal(lit) };

let ident_kind = ident_part().map(ExprKind::Ident);
let ident_kind = ident().map(ExprKind::Ident);

let internal = keyword("internal")
.ignore_then(ident())
Expand Down Expand Up @@ -69,7 +69,6 @@ pub(crate) fn expr() -> impl Parser<TokenKind, Expr, Error = PError> + Clone {
)
.boxed();

let term = field_lookup(term);
let term = unary(term);
let term = range(term);

Expand Down Expand Up @@ -170,28 +169,6 @@ where
.boxed()
}

fn field_lookup<'a, E>(expr: E) -> impl Parser<TokenKind, Expr, Error = PError> + Clone + 'a
where
E: Parser<TokenKind, Expr, Error = PError> + Clone + 'a,
{
expr.then(
ctrl('.')
.ignore_then(choice((
ident_part().map(IndirectionKind::Name),
ctrl('*').to(IndirectionKind::Star),
select! {
TokenKind::Literal(Literal::Integer(i)) => IndirectionKind::Position(i)
},
)))
.map_with_span(|f, s| (f, s))
.repeated(),
)
.foldl(|base, (field, span)| {
let base = Box::new(base);
ExprKind::Indirection { base, field }.into_expr(span)
})
}

fn range<'a, E>(expr: E) -> impl Parser<TokenKind, Expr, Error = PError> + Clone + 'a
where
E: Parser<TokenKind, Expr, Error = PError> + Clone + 'a,
Expand Down Expand Up @@ -522,8 +499,9 @@ where

pub(crate) fn ident() -> impl Parser<TokenKind, Ident, Error = PError> + Clone {
ident_part()
.separated_by(ctrl('.'))
.at_least(1)
.then_ignore(ctrl('.'))
.repeated()
.chain(choice((ident_part(), ctrl('*').map(|_| "*".to_string()))).map(Some))
.map(Ident::from_path::<String>)
}

Expand Down Expand Up @@ -583,7 +561,8 @@ mod tests {
@r#"
FuncCall:
name:
Ident: derive
Ident:
- derive
span: "0:0-6"
args:
- Literal:
Expand All @@ -598,16 +577,19 @@ mod tests {
@r#"
FuncCall:
name:
Ident: aggregate
Ident:
- aggregate
span: "0:0-9"
args:
- Tuple:
- FuncCall:
name:
Ident: sum
Ident:
- sum
span: "0:11-14"
args:
- Ident: salary
- Ident:
- salary
span: "0:15-21"
span: "0:11-21"
span: "0:10-22"
Expand All @@ -619,7 +601,8 @@ mod tests {
fn aliased_in_expr() {
assert_yaml_snapshot!(
parse_with_parser(r#"x = 5"#, trim_start().ignore_then(expr())).unwrap(), @r#"
Ident: x
Ident:
- x
span: "0:0-1"
"#);
}
Expand Down Expand Up @@ -670,17 +653,15 @@ mod tests {
Tuple:
- Pipeline:
exprs:
- Ident: d
- Ident:
- d
span: "0:10-11"
- FuncCall:
name:
Indirection:
base:
Ident: date
span: "0:14-18"
field:
Name: to_text
span: "0:18-26"
Ident:
- date
- to_text
span: "0:14-26"
args:
- Literal:
String: "%Y/%m/%d"
Expand Down Expand Up @@ -724,15 +705,18 @@ mod tests {
exprs:
- FuncCall:
name:
Ident: from
Ident:
- from
span: "0:29-33"
args:
- Ident: artists
- Ident:
- artists
span: "0:34-41"
span: "0:29-41"
- FuncCall:
name:
Ident: derive
Ident:
- derive
span: "0:56-62"
args:
- Literal:
Expand Down Expand Up @@ -762,15 +746,17 @@ mod tests {
- condition:
Binary:
left:
Ident: nickname
Ident:
- nickname
span: "0:30-38"
op: Ne
right:
Literal: "Null"
span: "0:42-46"
span: "0:30-46"
value:
Ident: nickname
Ident:
- nickname
span: "0:50-58"
- condition:
Literal:
Expand Down Expand Up @@ -849,12 +835,15 @@ mod tests {
parse_with_parser(r#"f (a) b"#, trim_start().ignore_then(expr_call()).then_ignore(end())).unwrap(), @r#"
FuncCall:
name:
Ident: f
Ident:
- f
span: "0:0-1"
args:
- Ident: a
- Ident:
- a
span: "0:3-4"
- Ident: b
- Ident:
- b
span: "0:6-7"
span: "0:0-7"
"#);
Expand All @@ -863,14 +852,16 @@ mod tests {
parse_with_parser(r#"f (a=2) b"#, trim_start().ignore_then(expr_call()).then_ignore(end())).unwrap(), @r#"
FuncCall:
name:
Ident: f
Ident:
- f
span: "0:0-1"
args:
- Literal:
Integer: 2
span: "0:5-6"
alias: a
- Ident: b
- Ident:
- b
span: "0:8-9"
span: "0:0-9"
"#);
Expand All @@ -879,15 +870,18 @@ mod tests {
parse_with_parser(r#"f (a b)"#, trim_start().ignore_then(expr_call()).then_ignore(end())).unwrap(), @r#"
FuncCall:
name:
Ident: f
Ident:
- f
span: "0:0-1"
args:
- FuncCall:
name:
Ident: a
Ident:
- a
span: "0:3-4"
args:
- Ident: b
- Ident:
- b
span: "0:5-6"
span: "0:3-6"
span: "0:0-7"
Expand All @@ -906,20 +900,19 @@ mod tests {
assert_yaml_snapshot!(parse_with_parser(source, trim_start().ignore_then(pipeline(expr_call()))).unwrap(), @r#"
Pipeline:
exprs:
- Ident: tbl
- Ident:
- tbl
span: "0:13-16"
- FuncCall:
name:
Ident: select
Ident:
- select
span: "0:23-29"
args:
- Indirection:
base:
Ident: t
span: "0:30-31"
field:
Name: date
span: "0:31-36"
- Ident:
- t
- date
span: "0:30-36"
span: "0:23-36"
span: "0:5-42"
"#);
Expand All @@ -934,21 +927,20 @@ mod tests {
assert_yaml_snapshot!(parse_with_parser(source, trim_start().ignore_then(pipeline(expr_call()))).unwrap(), @r#"
Pipeline:
exprs:
- Ident: tbl
- Ident:
- tbl
span: "0:17-20"
alias: t
- FuncCall:
name:
Ident: select
Ident:
- select
span: "0:27-33"
args:
- Indirection:
base:
Ident: t
span: "0:34-35"
field:
Name: date
span: "0:35-40"
- Ident:
- t
- date
span: "0:34-40"
span: "0:27-40"
span: "0:5-46"
"#);
Expand Down
25 changes: 10 additions & 15 deletions prqlc/prqlc-parser/src/parser/interpolation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,12 @@ pub(crate) fn parse(string: String, span_base: Span) -> Result<Vec<InterpolateIt

fn interpolated_parser() -> impl Parser<char, Vec<InterpolateItem>, Error = ChumError<char>> {
let expr = interpolate_ident_part()
.map_with_span(move |name, s| (name, s))
.separated_by(just('.'))
.at_least(1)
.map(|ident_parts| {
let mut parts = ident_parts.into_iter();

let (first, first_span) = parts.next().unwrap();
let mut base = Box::new(ExprKind::Ident(first).into_expr(first_span));

for (part, span) in parts {
let field = IndirectionKind::Name(part);
base = Box::new(ExprKind::Indirection { base, field }.into_expr(span));
}
base
})
.map(Ident::from_path)
.map(ExprKind::Ident)
.map_with_span(ExprKind::into_expr)
.map(Box::new)
.labelled("interpolated string variable")
.then(
just(':')
Expand Down Expand Up @@ -92,7 +83,9 @@ fn parse_interpolate() {
Expr {
expr: Expr {
kind: Ident(
"a",
[
"a",
],
),
span: Some(
0:8-9,
Expand Down Expand Up @@ -138,7 +131,9 @@ fn parse_interpolate() {
Expr {
expr: Expr {
kind: Ident(
"a",
[
"a",
],
),
span: Some(
0:14-15,
Expand Down
12 changes: 3 additions & 9 deletions prqlc/prqlc-parser/src/parser/pr/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};

use crate::lexer::lr::Literal;
use crate::parser::pr::ops::{BinOp, UnOp};
use crate::parser::pr::Ty;
use crate::parser::pr::{Ident, Ty};
use crate::span::Span;
use crate::{generic, parser::SupportsDocComment};

Expand Down Expand Up @@ -53,14 +53,8 @@ impl SupportsDocComment for Expr {
Debug, EnumAsInner, PartialEq, Clone, Serialize, Deserialize, strum::AsRefStr, JsonSchema,
)]
pub enum ExprKind {
Ident(String),

/// A lookup into an object by name or position.
/// Currently, this includes only tuple field lookups, primarily by name.
Indirection {
base: Box<Expr>,
field: IndirectionKind,
},
Ident(Ident),

#[cfg_attr(
feature = "serde_yaml",
serde(with = "serde_yaml::with::singleton_map"),
Expand Down
Loading
Loading