diff --git a/prqlc/prqlc-parser/src/error.rs b/prqlc/prqlc-parser/src/error.rs index f9d255f856fd..9298ccc7e96d 100644 --- a/prqlc/prqlc-parser/src/error.rs +++ b/prqlc/prqlc-parser/src/error.rs @@ -46,8 +46,12 @@ pub enum MessageKind { pub enum Reason { Simple(String), Expected { + /// Where we were + // (could rename to `where` / `location` / `within`?) who: Option, + /// What we expected expected: String, + /// What we found found: String, }, Unexpected { diff --git a/prqlc/prqlc-parser/src/lexer/mod.rs b/prqlc/prqlc-parser/src/lexer/mod.rs index 494ea9d86e54..6f7a0eed1afd 100644 --- a/prqlc/prqlc-parser/src/lexer/mod.rs +++ b/prqlc/prqlc-parser/src/lexer/mod.rs @@ -184,6 +184,9 @@ fn line_wrap() -> impl Parser> { fn comment() -> impl Parser> { just('#').ignore_then(choice(( + // One option would be to check that doc comments have new lines in the + // lexer (we currently do in the parser); which would give better error + // messages? just('!').ignore_then( newline() .not() diff --git a/prqlc/prqlc-parser/src/parser/common.rs b/prqlc/prqlc-parser/src/parser/common.rs index 95b522649302..802a5c42e33e 100644 --- a/prqlc/prqlc-parser/src/parser/common.rs +++ b/prqlc/prqlc-parser/src/parser/common.rs @@ -5,8 +5,10 @@ use super::pr::{Annotation, Stmt, StmtKind}; use crate::lexer::lr::TokenKind; use crate::span::Span; -pub fn ident_part() -> impl Parser + Clone { - return select! { +use super::SupportsDocComment; + +pub(crate) fn ident_part() -> impl Parser + Clone { + select! { TokenKind::Ident(ident) => ident, TokenKind::Keyword(ident) if &ident == "module" => ident, } @@ -16,18 +18,27 @@ pub fn ident_part() -> impl Parser + Clone { [Some(TokenKind::Ident("".to_string()))], e.found().cloned(), ) - }); + }) } -pub fn keyword(kw: &'static str) -> impl Parser + Clone { +pub(crate) fn keyword(kw: &'static str) -> impl Parser + Clone { just(TokenKind::Keyword(kw.to_string())).ignored() } +/// Our approach to new lines is each item consumes new lines _before_ itself, +/// but not newlines after itself. This allows us to enforce new lines between +/// some items. The only place we handle new lines after an item is in the root +/// parser. pub fn new_line() -> impl Parser + Clone { - just(TokenKind::NewLine).ignored() + just(TokenKind::NewLine) + // Start is considered a new line, so we can enforce things start on a new + // line while allowing them to be at the beginning of a file + .or(just(TokenKind::Start)) + .ignored() + .labelled("new line") } -pub fn ctrl(char: char) -> impl Parser + Clone { +pub(crate) fn ctrl(char: char) -> impl Parser + Clone { just(TokenKind::Control(char)).ignored() } @@ -36,5 +47,77 @@ pub fn into_stmt((annotations, kind): (Vec, StmtKind), span: Span) - kind, span: Some(span), annotations, + doc_comment: None, + } +} + +pub(crate) fn doc_comment() -> impl Parser + Clone { + // doc comments must start on a new line, so we enforce a new line (which + // can also be a file start) before the doc comment + // + // TODO: we currently lose any empty newlines between doc comments; + // eventually we want to retain them + (new_line().repeated().at_least(1).ignore_then(select! { + TokenKind::DocComment(dc) => dc, + })) + .repeated() + .at_least(1) + .collect() + .map(|lines: Vec| lines.join("\n")) + .labelled("doc comment") +} + +pub(crate) fn with_doc_comment<'a, P, O>( + parser: P, +) -> impl Parser + Clone + 'a +where + P: Parser + Clone + 'a, + O: SupportsDocComment + 'a, +{ + doc_comment() + .or_not() + .then(parser) + .map(|(doc_comment, inner)| inner.with_doc_comment(doc_comment)) +} + +#[cfg(test)] +mod tests { + use insta::assert_debug_snapshot; + + use super::*; + use crate::test::parse_with_parser; + + #[test] + fn test_doc_comment() { + assert_debug_snapshot!(parse_with_parser(r#" + #! doc comment + #! another line + + "#, doc_comment()), @r###" + Ok( + " doc comment\n another line", + ) + "###); + } + + #[test] + fn test_doc_comment_or_not() { + assert_debug_snapshot!(parse_with_parser(r#"hello"#, doc_comment().or_not()).unwrap(), @"None"); + assert_debug_snapshot!(parse_with_parser(r#"hello"#, doc_comment().or_not().then_ignore(new_line().repeated()).then(ident_part())).unwrap(), @r###" + ( + None, + "hello", + ) + "###); + } + + #[test] + fn test_no_doc_comment_in_with_doc_comment() { + impl SupportsDocComment for String { + fn with_doc_comment(self, _doc_comment: Option) -> Self { + self + } + } + assert_debug_snapshot!(parse_with_parser(r#"hello"#, with_doc_comment(new_line().ignore_then(ident_part()))).unwrap(), @r###""hello""###); } } diff --git a/prqlc/prqlc-parser/src/parser/expr.rs b/prqlc/prqlc-parser/src/parser/expr.rs index 58d8bafb7b6b..278d90183046 100644 --- a/prqlc/prqlc-parser/src/parser/expr.rs +++ b/prqlc/prqlc-parser/src/parser/expr.rs @@ -3,13 +3,11 @@ use std::collections::HashMap; use chumsky::prelude::*; use itertools::Itertools; -use super::interpolation; use crate::lexer::lr::{Literal, TokenKind}; -use crate::parser::common::{ctrl, ident_part, keyword, new_line}; +use crate::parser::common::{ctrl, ident_part, keyword, new_line, with_doc_comment}; +use crate::parser::interpolation; use crate::parser::perror::PError; -use crate::parser::pr::Ident; use crate::parser::pr::*; -use crate::parser::pr::{BinOp, UnOp}; use crate::parser::types::type_expr; use crate::span::Span; @@ -30,7 +28,9 @@ pub fn expr() -> impl Parser + Clone { .map(|x| x.to_string()) .map(ExprKind::Internal); - let nested_expr = pipeline(lambda_func(expr.clone()).or(func_call(expr.clone()))).boxed(); + let nested_expr = with_doc_comment( + pipeline(lambda_func(expr.clone()).or(func_call(expr.clone()))).boxed(), + ); let tuple = tuple(nested_expr.clone()); let array = array(nested_expr.clone()); @@ -40,18 +40,20 @@ pub fn expr() -> impl Parser + Clone { let param = select! { TokenKind::Param(id) => ExprKind::Param(id) }; - let term = choice(( - literal, - internal, - tuple, - array, - interpolation, - ident_kind, - case, - param, - )) - .map_with_span(ExprKind::into_expr) - .or(pipeline_expr) + let term = with_doc_comment( + choice(( + literal, + internal, + tuple, + array, + interpolation, + ident_kind, + case, + param, + )) + .map_with_span(ExprKind::into_expr) + .or(pipeline_expr), + ) .boxed(); let term = field_lookup(term); @@ -74,12 +76,15 @@ pub fn expr() -> impl Parser + Clone { fn tuple( nested_expr: impl Parser + Clone, ) -> impl Parser + Clone { - ident_part() - .then_ignore(ctrl('=')) - .or_not() - .then(nested_expr) - .map(|(alias, expr)| Expr { alias, ..expr }) - .padded_by(new_line().repeated()) + new_line() + .repeated() + .ignore_then( + ident_part() + .then_ignore(ctrl('=')) + .or_not() + .then(nested_expr) + .map(|(alias, expr)| Expr { alias, ..expr }), + ) .separated_by(ctrl(',')) .allow_trailing() .then_ignore(new_line().repeated()) @@ -101,22 +106,25 @@ fn tuple( fn array( expr: impl Parser + Clone, ) -> impl Parser + Clone { - expr.padded_by(new_line().repeated()) - .separated_by(ctrl(',')) - .allow_trailing() - .then_ignore(new_line().repeated()) - .delimited_by(ctrl('['), ctrl(']')) - .recover_with(nested_delimiters( - TokenKind::Control('['), - TokenKind::Control(']'), - [ - (TokenKind::Control('{'), TokenKind::Control('}')), - (TokenKind::Control('('), TokenKind::Control(')')), - (TokenKind::Control('['), TokenKind::Control(']')), - ], - |_| vec![], - )) - .map(ExprKind::Array) + new_line() + .repeated() + .ignore_then( + expr.separated_by(ctrl(',')) + .allow_trailing() + .then_ignore(new_line().repeated()) + .delimited_by(ctrl('['), ctrl(']')) + .recover_with(nested_delimiters( + TokenKind::Control('['), + TokenKind::Control(']'), + [ + (TokenKind::Control('{'), TokenKind::Control('}')), + (TokenKind::Control('('), TokenKind::Control(')')), + (TokenKind::Control('['), TokenKind::Control(']')), + ], + |_| vec![], + )) + .map(ExprKind::Array), + ) .labelled("array") } @@ -158,17 +166,19 @@ fn interpolation() -> impl Parser + Clone { fn case( expr: impl Parser + Clone, ) -> impl Parser + Clone { + // The `nickname != null => nickname,` part + let mapping = func_call(expr.clone()) + .map(Box::new) + .then_ignore(just(TokenKind::ArrowFat)) + .then(func_call(expr).map(Box::new)) + .map(|(condition, value)| SwitchCase { condition, value }); + keyword("case") .ignore_then( - func_call(expr.clone()) - .map(Box::new) - .then_ignore(just(TokenKind::ArrowFat)) - .then(func_call(expr).map(Box::new)) - .map(|(condition, value)| SwitchCase { condition, value }) - .padded_by(new_line().repeated()) - .separated_by(ctrl(',')) + mapping + .separated_by(ctrl(',').then_ignore(new_line().repeated())) .allow_trailing() - .then_ignore(new_line().repeated()) + .padded_by(new_line().repeated()) .delimited_by(ctrl('['), ctrl(']')), ) .map(ExprKind::Case) @@ -274,29 +284,29 @@ where new_line().repeated().at_least(1).ignored(), )); - new_line() - .repeated() - .ignore_then( + with_doc_comment( + new_line().repeated().ignore_then( ident_part() .then_ignore(ctrl('=')) .or_not() .then(expr) - .map(|(alias, expr)| Expr { alias, ..expr }) - .separated_by(pipe) - .at_least(1) - .map_with_span(|exprs, span| { - // If there's only one expr, then we don't need to wrap it - // in a pipeline — just return the lone expr. Otherwise, - // wrap them in a pipeline. - exprs.into_iter().exactly_one().unwrap_or_else(|exprs| { - ExprKind::Pipeline(Pipeline { - exprs: exprs.collect(), - }) - .into_expr(span) - }) - }), - ) - .labelled("pipeline") + .map(|(alias, expr)| Expr { alias, ..expr }), + ), + ) + .separated_by(pipe) + .at_least(1) + .map_with_span(|exprs, span| { + // If there's only one expr, then we don't need to wrap it + // in a pipeline — just return the lone expr. Otherwise, + // wrap them in a pipeline. + exprs.into_iter().exactly_one().unwrap_or_else(|exprs| { + ExprKind::Pipeline(Pipeline { + exprs: exprs.collect(), + }) + .into_expr(span) + }) + }) + .labelled("pipeline") } fn binary_op_parser<'a, Term, Op>( @@ -543,3 +553,114 @@ fn operator_or() -> impl Parser + Clone { fn operator_coalesce() -> impl Parser + Clone { just(TokenKind::Coalesce).to(BinOp::Coalesce) } + +#[cfg(test)] +mod tests { + + use insta::assert_yaml_snapshot; + + use crate::test::{parse_with_parser, trim_start}; + + use super::*; + + #[test] + fn test_expr() { + assert_yaml_snapshot!( + parse_with_parser(r#"5+5"#, trim_start().ignore_then(expr())).unwrap(), + @r###" + --- + Binary: + left: + Literal: + Integer: 5 + span: "0:0-1" + op: Add + right: + Literal: + Integer: 5 + span: "0:2-3" + span: "0:0-3" + "###); + + assert_yaml_snapshot!( + parse_with_parser(r#"derive x = 5"#, trim_start().ignore_then(expr())).unwrap(), + @r###" + --- + Ident: derive + span: "0:0-6" + "###); + } + + #[test] + fn test_pipeline() { + assert_yaml_snapshot!( + parse_with_parser(r#" + from artists + derive x = 5 + "#, trim_start().then(pipeline(expr_call()))).unwrap(), + @r###" + --- + - ~ + - Pipeline: + exprs: + - FuncCall: + name: + Ident: from + span: "0:13-17" + args: + - Ident: artists + span: "0:18-25" + span: "0:13-25" + - FuncCall: + name: + Ident: derive + span: "0:38-44" + args: + - Literal: + Integer: 5 + span: "0:49-50" + alias: x + span: "0:38-50" + span: "0:13-50" + "###); + } + + #[test] + fn test_case() { + assert_yaml_snapshot!( + parse_with_parser(r#" + + case [ + + nickname != null => nickname, + true => null + + ] + "#, trim_start().then(case(expr()))).unwrap(), + @r###" + --- + - ~ + - Case: + - condition: + Binary: + left: + Ident: nickname + span: "0:30-38" + op: Ne + right: + Literal: "Null" + span: "0:42-46" + span: "0:30-46" + value: + Ident: nickname + span: "0:50-58" + - condition: + Literal: + Boolean: true + span: "0:72-76" + value: + Literal: "Null" + span: "0:80-84" + "###); + } +} diff --git a/prqlc/prqlc-parser/src/parser/interpolation.rs b/prqlc/prqlc-parser/src/parser/interpolation.rs index 53c91dcc1828..a5c518054f02 100644 --- a/prqlc/prqlc-parser/src/parser/interpolation.rs +++ b/prqlc/prqlc-parser/src/parser/interpolation.rs @@ -97,6 +97,7 @@ fn parse_interpolate() { 0:8-9, ), alias: None, + doc_comment: None, }, format: None, }, @@ -142,6 +143,7 @@ fn parse_interpolate() { 0:14-15, ), alias: None, + doc_comment: None, }, format: None, }, diff --git a/prqlc/prqlc-parser/src/parser/mod.rs b/prqlc/prqlc-parser/src/parser/mod.rs index 23fa466b70f9..bc102306ed47 100644 --- a/prqlc/prqlc-parser/src/parser/mod.rs +++ b/prqlc/prqlc-parser/src/parser/mod.rs @@ -1,5 +1,6 @@ use chumsky::{prelude::*, Stream}; +pub use self::common::new_line; use crate::error::Error; use crate::lexer::lr; use crate::span::Span; @@ -43,10 +44,7 @@ pub(crate) fn prepare_stream( let semantic_tokens = tokens.filter(|token| { !matches!( token.kind, - lr::TokenKind::Comment(_) - | lr::TokenKind::LineWrap(_) - | lr::TokenKind::DocComment(_) - | lr::TokenKind::Start + lr::TokenKind::Comment(_) | lr::TokenKind::LineWrap(_) ) }); @@ -61,3 +59,7 @@ pub(crate) fn prepare_stream( }; Stream::from_iter(eoi, tokens) } + +pub trait SupportsDocComment { + fn with_doc_comment(self, doc_comment: Option) -> Self; +} diff --git a/prqlc/prqlc-parser/src/parser/perror.rs b/prqlc/prqlc-parser/src/parser/perror.rs index 35056a5f091b..973aee315857 100644 --- a/prqlc/prqlc-parser/src/parser/perror.rs +++ b/prqlc/prqlc-parser/src/parser/perror.rs @@ -138,9 +138,7 @@ impl chumsky::Error for ChumError { }); self.label = self.label.merge(other.label); - for expected in other.expected { - self.expected.insert(expected); - } + self.expected.extend(other.expected); self } } diff --git a/prqlc/prqlc-parser/src/parser/pr/expr.rs b/prqlc/prqlc-parser/src/parser/pr/expr.rs index d4eb8d8c8a26..cef555076ac9 100644 --- a/prqlc/prqlc-parser/src/parser/pr/expr.rs +++ b/prqlc/prqlc-parser/src/parser/pr/expr.rs @@ -8,6 +8,7 @@ use crate::generic; use crate::lexer::lr::Literal; use crate::parser::pr::ops::{BinOp, UnOp}; use crate::parser::pr::Ty; +use crate::parser::SupportsDocComment; use crate::span::Span; impl Expr { @@ -16,6 +17,7 @@ impl Expr { kind: kind.into(), span: None, alias: None, + doc_comment: None, } } } @@ -34,6 +36,18 @@ pub struct Expr { #[serde(skip_serializing_if = "Option::is_none")] pub alias: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub doc_comment: Option, +} + +impl SupportsDocComment for Expr { + fn with_doc_comment(self, doc_comment: Option) -> Self { + Self { + doc_comment, + ..self + } + } } #[derive( @@ -81,6 +95,7 @@ impl ExprKind { span: Some(span), kind: self, alias: None, + doc_comment: None, } } } diff --git a/prqlc/prqlc-parser/src/parser/pr/stmt.rs b/prqlc/prqlc-parser/src/parser/pr/stmt.rs index faf208a4939b..878d5788a1b4 100644 --- a/prqlc/prqlc-parser/src/parser/pr/stmt.rs +++ b/prqlc/prqlc-parser/src/parser/pr/stmt.rs @@ -5,8 +5,8 @@ use schemars::JsonSchema; use semver::VersionReq; use serde::{Deserialize, Serialize}; -use crate::parser::pr::ident::Ident; use crate::parser::pr::{Expr, Ty}; +use crate::parser::{pr::ident::Ident, SupportsDocComment}; use crate::span::Span; #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, Default, JsonSchema)] @@ -35,6 +35,18 @@ pub struct Stmt { #[serde(skip_serializing_if = "Vec::is_empty", default)] pub annotations: Vec, + + #[serde(skip_serializing_if = "Option::is_none")] + pub doc_comment: Option, +} + +impl SupportsDocComment for Stmt { + fn with_doc_comment(self, doc_comment: Option) -> Self { + Stmt { + doc_comment, + ..self + } + } } #[derive(Debug, EnumAsInner, PartialEq, Clone, Serialize, Deserialize, JsonSchema)] @@ -85,6 +97,7 @@ impl Stmt { kind, span: None, annotations: Vec::new(), + doc_comment: None, } } } diff --git a/prqlc/prqlc-parser/src/parser/stmt.rs b/prqlc/prqlc-parser/src/parser/stmt.rs index e1fe38301e3d..23f343acf37c 100644 --- a/prqlc/prqlc-parser/src/parser/stmt.rs +++ b/prqlc/prqlc-parser/src/parser/stmt.rs @@ -4,17 +4,20 @@ use chumsky::prelude::*; use itertools::Itertools; use semver::VersionReq; -use super::common::{ctrl, ident_part, into_stmt, keyword, new_line}; +use super::common::{ctrl, ident_part, into_stmt, keyword, new_line, with_doc_comment}; use super::expr::{expr, expr_call, ident, pipeline}; use crate::lexer::lr::{Literal, TokenKind}; use crate::parser::perror::PError; use crate::parser::pr::*; use crate::parser::types::type_expr; -pub(crate) fn source() -> impl Parser, Error = PError> { - query_def() +pub fn source() -> impl Parser, Error = PError> { + with_doc_comment(query_def()) .or_not() .chain(module_contents()) + // This is the only instance we can consume newlines at the end of something, since + // this is the end of the module + .then_ignore(new_line().repeated()) .then_ignore(end()) } @@ -22,30 +25,57 @@ fn module_contents() -> impl Parser, Error = PError> { recursive(|module_contents| { let module_def = keyword("module") .ignore_then(ident_part()) - .then(module_contents.delimited_by(ctrl('{'), ctrl('}'))) + .then( + module_contents + .then_ignore(new_line().repeated()) + .delimited_by(ctrl('{'), ctrl('}')), + ) .map(|(name, stmts)| StmtKind::ModuleDef(ModuleDef { name, stmts })) .labelled("module definition"); - let annotation = just(TokenKind::Annotate) - .ignore_then(expr()) - .then_ignore(new_line().repeated()) - .map(|expr| Annotation { - expr: Box::new(expr), - }); - - annotation + let annotation = new_line() .repeated() - .then(choice((module_def, type_def(), import_def(), var_def()))) - .map_with_span(into_stmt) - .separated_by(new_line().repeated().at_least(1)) - .allow_leading() - .allow_trailing() + // TODO: we could enforce annotations starting on a new line? + // .at_least(1) + .ignore_then( + just(TokenKind::Annotate) + .ignore_then(expr()) + .map(|expr| Annotation { + expr: Box::new(expr), + }), + ) + .labelled("annotation"); + + // TODO: we want to confirm that we're not allowing things on the same + // line that should't be; e.g. `let foo = 5 let bar = 6`. We can't + // enforce a new line here because then `module two {let houses = + // both.alike}` fails (though we could force a new line after the + // `module` if that were helpful) + // + // let stmt_kind = new_line().repeated().at_least(1).ignore_then(choice(( + let stmt_kind = new_line().repeated().ignore_then(choice(( + module_def, + type_def(), + import_def(), + var_def(), + ))); + + // Currently doc comments need to be before the annotation; probably + // should relax this? + with_doc_comment( + annotation + .repeated() + .then(stmt_kind) + .map_with_span(into_stmt), + ) + .repeated() }) } fn query_def() -> impl Parser + Clone { new_line() .repeated() + .at_least(1) .ignore_then(keyword("prql")) .ignore_then( // named arg @@ -113,7 +143,9 @@ fn query_def() -> impl Parser + Clone { } fn var_def() -> impl Parser + Clone { - let let_ = keyword("let") + let let_ = new_line() + .repeated() + .ignore_then(keyword("let")) .ignore_then(ident_part()) .then(type_expr().delimited_by(ctrl('<'), ctrl('>')).or_not()) .then(ctrl('=').ignore_then(expr_call()).map(Box::new).or_not()) @@ -128,9 +160,13 @@ fn var_def() -> impl Parser + Clone { .labelled("variable definition"); let main_or_into = pipeline(expr_call()) - .then_ignore(new_line().repeated()) .map(Box::new) - .then(keyword("into").ignore_then(ident_part()).or_not()) + .then( + new_line() + .repeated() + .ignore_then(keyword("into").ignore_then(ident_part())) + .or_not(), + ) .map(|(value, name)| { let kind = if name.is_none() { VarDefKind::Main @@ -146,6 +182,8 @@ fn var_def() -> impl Parser + Clone { ty: None, }) }) + // TODO: this isn't really accurate, since a standard `from artists` + // also counts as this; we should change .labelled("variable definition"); let_.or(main_or_into) @@ -166,3 +204,167 @@ fn import_def() -> impl Parser + Clone { .map(|(alias, name)| StmtKind::ImportDef(ImportDef { name, alias })) .labelled("import statement") } + +#[cfg(test)] +mod tests { + use insta::assert_yaml_snapshot; + + use super::*; + use crate::test::parse_with_parser; + + #[test] + fn test_module_contents() { + assert_yaml_snapshot!(parse_with_parser(r#" + let world = 1 + let man = module.world + "#, module_contents()).unwrap(), @r###" + --- + - VarDef: + kind: Let + name: world + value: + Literal: + Integer: 1 + span: "0:25-26" + span: "0:0-26" + - VarDef: + kind: Let + name: man + value: + Indirection: + base: + Ident: module + span: "0:49-55" + field: + Name: world + span: "0:49-61" + span: "0:26-61" + "###); + } + + #[test] + fn test_module_def() { + // Same line + assert_yaml_snapshot!(parse_with_parser(r#"module two {let houses = both.alike} + "#, module_contents()).unwrap(), @r###" + --- + - ModuleDef: + name: two + stmts: + - VarDef: + kind: Let + name: houses + value: + Indirection: + base: + Ident: both + span: "0:25-29" + field: + Name: alike + span: "0:25-35" + span: "0:12-35" + span: "0:0-36" + "###); + + assert_yaml_snapshot!(parse_with_parser(r#" + module dignity { + let fair = 1 + let verona = we.lay + } + "#, module_contents()).unwrap(), @r###" + --- + - ModuleDef: + name: dignity + stmts: + - VarDef: + kind: Let + name: fair + value: + Literal: + Integer: 1 + span: "0:51-52" + span: "0:27-52" + - VarDef: + kind: Let + name: verona + value: + Indirection: + base: + Ident: we + span: "0:78-80" + field: + Name: lay + span: "0:78-84" + span: "0:52-84" + span: "0:0-95" + "###); + } + + #[test] + fn test_doc_comment_module() { + assert_yaml_snapshot!(parse_with_parser(r#" + + #! first doc comment + from foo + + "#, module_contents()).unwrap(), @r###" + --- + - VarDef: + kind: Main + name: main + value: + FuncCall: + name: + Ident: from + span: "0:39-43" + args: + - Ident: foo + span: "0:44-47" + span: "0:39-47" + span: "0:30-47" + doc_comment: " first doc comment" + "###); + + assert_yaml_snapshot!(parse_with_parser(r#" + + + #! first doc comment + from foo + into x + + #! second doc comment + from bar + + "#, module_contents()).unwrap(), @r###" + --- + - VarDef: + kind: Into + name: x + value: + FuncCall: + name: + Ident: from + span: "0:40-44" + args: + - Ident: foo + span: "0:45-48" + span: "0:40-48" + span: "0:31-63" + doc_comment: " first doc comment" + - VarDef: + kind: Main + name: main + value: + FuncCall: + name: + Ident: from + span: "0:103-107" + args: + - Ident: bar + span: "0:108-111" + span: "0:103-111" + span: "0:94-111" + doc_comment: " second doc comment" + "###); + } +} diff --git a/prqlc/prqlc-parser/src/parser/test.rs b/prqlc/prqlc-parser/src/parser/test.rs index 0d6ff9963f0f..2d8a71839f0f 100644 --- a/prqlc/prqlc-parser/src/parser/test.rs +++ b/prqlc/prqlc-parser/src/parser/test.rs @@ -1,3 +1,4 @@ +use chumsky::Parser; use insta::assert_yaml_snapshot; use crate::parser::prepare_stream; @@ -6,10 +7,13 @@ use crate::test::parse_with_parser; use crate::{error::Error, lexer::lex_source}; use crate::{lexer::lr::TokenKind, parser::pr::FuncCall}; -use super::pr::Expr; +use super::{common::new_line, pr::Expr}; fn parse_expr(source: &str) -> Result> { - parse_with_parser(source, super::expr::expr_call()) + parse_with_parser( + source, + new_line().repeated().ignore_then(super::expr::expr_call()), + ) } #[test] @@ -22,6 +26,8 @@ fn test_prepare_stream() { let mut stream = prepare_stream(tokens.0.into_iter(), input, 0); assert_yaml_snapshot!(stream.fetch_tokens().collect::>(), @r###" --- + - - Start + - "0:0-0" - - Ident: from - "0:0-4" - - Ident: artists @@ -1249,33 +1255,35 @@ fn test_ident_with_keywords() { #[test] fn test_case() { - assert_yaml_snapshot!(parse_expr(r#"case [ + assert_yaml_snapshot!(parse_expr(r#" + case [ nickname != null => nickname, true => null - ]"#).unwrap(), @r###" + ] + "#).unwrap(), @r###" --- Case: - condition: Binary: left: Ident: nickname - span: "0:19-27" + span: "0:28-36" op: Ne right: Literal: "Null" - span: "0:31-35" - span: "0:19-35" + span: "0:40-44" + span: "0:28-44" value: Ident: nickname - span: "0:39-47" + span: "0:48-56" - condition: Literal: Boolean: true - span: "0:61-65" + span: "0:70-74" value: Literal: "Null" - span: "0:69-73" - span: "0:0-83" + span: "0:78-82" + span: "0:9-92" "###); } diff --git a/prqlc/prqlc-parser/src/snapshots/prqlc_parser__test__pipeline_parse_tree.snap b/prqlc/prqlc-parser/src/snapshots/prqlc_parser__test__pipeline_parse_tree.snap index 84bca84aeba0..38604e50876c 100644 --- a/prqlc/prqlc-parser/src/snapshots/prqlc_parser__test__pipeline_parse_tree.snap +++ b/prqlc/prqlc-parser/src/snapshots/prqlc_parser__test__pipeline_parse_tree.snap @@ -188,4 +188,4 @@ expression: "parse_single(r#\"\nfrom employees\nfilter country == \"USA\" span: "0:711-713" span: "0:706-713" span: "0:1-713" - span: "0:1-714" + span: "0:0-713" diff --git a/prqlc/prqlc-parser/src/test.rs b/prqlc/prqlc-parser/src/test.rs index 65937607de0c..0593c577e336 100644 --- a/prqlc/prqlc-parser/src/test.rs +++ b/prqlc/prqlc-parser/src/test.rs @@ -1,6 +1,8 @@ use chumsky::Parser; use insta::{assert_debug_snapshot, assert_yaml_snapshot}; +use std::fmt::Debug; +use crate::parser::new_line; use crate::parser::pr::Stmt; use crate::parser::prepare_stream; use crate::parser::stmt; @@ -9,26 +11,34 @@ use crate::{error::Error, lexer::lr::TokenKind, parser::perror::PError}; /// Parse source code based on the supplied parser. /// /// Use this to test any parser! -pub(crate) fn parse_with_parser( +pub(crate) fn parse_with_parser( source: &str, parser: impl Parser, ) -> Result> { let tokens = crate::lexer::lex_source(source)?; let stream = prepare_stream(tokens.0.into_iter(), source, 0); - let (ast, parse_errors) = parser.parse_recovery(stream); + let (ast, parse_errors) = parser.parse_recovery_verbose(stream); if !parse_errors.is_empty() { + log::info!("ast: {ast:?}"); return Err(parse_errors.into_iter().map(|e| e.into()).collect()); } Ok(ast.unwrap()) } /// Parse into statements -fn parse_single(source: &str) -> Result, Vec> { +pub(crate) fn parse_single(source: &str) -> Result, Vec> { + // parse_with_parser(source, new_line().repeated().ignore_then(stmt::source())) parse_with_parser(source, stmt::source()) } +// TODO: move to expr singe stmts don't need it? +/// Remove leading newlines & the start token, for tests +pub(crate) fn trim_start() -> impl Parser { + new_line().repeated().ignored() +} + #[test] fn test_error_unicode_string() { // Test various unicode strings successfully parse errors. We were @@ -79,7 +89,7 @@ fn test_error_unexpected() { 0:6-7, ), reason: Simple( - "unexpected : while parsing function call", + "unexpected :", ), hints: [], code: None, @@ -363,7 +373,7 @@ fn test_basic_exprs() { - Ident: a span: "0:35-36" span: "0:28-36" - span: "0:28-36" + span: "0:0-36" "###); } @@ -541,7 +551,7 @@ fn test_function() { named_params: [] generic_type_params: [] span: "0:0-27" - span: "0:0-28" + span: "0:0-27" "###); assert_yaml_snapshot!(parse_single(r#"let count = X -> s"SUM({X})" @@ -633,7 +643,7 @@ fn test_function() { named_params: [] generic_type_params: [] span: "0:27-147" - span: "0:13-147" + span: "0:0-147" "###); assert_yaml_snapshot!(parse_single("let add = x to:a -> x + to\n").unwrap(), @r###" @@ -774,7 +784,7 @@ fn test_var_def() { SString: - String: SELECT * FROM employees span: "0:21-47" - span: "0:13-47" + span: "0:0-47" "###); assert_yaml_snapshot!(parse_single( @@ -826,7 +836,7 @@ fn test_var_def() { - Ident: x span: "0:101-102" span: "0:96-102" - span: "0:96-102" + span: "0:84-102" "###); } @@ -916,7 +926,7 @@ fn test_sql_parameters() { span: "0:37-107" span: "0:30-107" span: "0:9-107" - span: "0:9-108" + span: "0:0-107" "###); } @@ -1017,7 +1027,7 @@ join `my-proj`.`dataset`.`table` span: "0:118-126" span: "0:94-126" span: "0:1-126" - span: "0:1-127" + span: "0:0-126" "###); } @@ -1113,7 +1123,7 @@ fn test_sort() { span: "0:136-174" span: "0:131-174" span: "0:9-174" - span: "0:9-175" + span: "0:0-174" "###); } @@ -1160,7 +1170,7 @@ fn test_dates() { span: "0:39-76" span: "0:32-76" span: "0:9-76" - span: "0:9-77" + span: "0:0-76" "###); } @@ -1184,7 +1194,7 @@ fn test_multiline_string() { span: "0:20-36" alias: x span: "0:9-36" - span: "0:9-37" + span: "0:0-36" "### ) } @@ -1225,7 +1235,7 @@ derive x = 5 alias: x span: "0:14-26" span: "0:1-26" - span: "0:1-31" + span: "0:0-26" "### ) } @@ -1268,7 +1278,7 @@ fn test_coalesce() { alias: amount span: "0:32-59" span: "0:9-59" - span: "0:9-60" + span: "0:0-59" "### ) } @@ -1292,7 +1302,7 @@ fn test_literal() { span: "0:20-24" alias: x span: "0:9-24" - span: "0:9-25" + span: "0:0-24" "###) } @@ -1364,7 +1374,7 @@ fn test_allowed_idents() { span: "0:140-172" span: "0:133-172" span: "0:9-172" - span: "0:9-173" + span: "0:0-172" "###) } @@ -1457,7 +1467,7 @@ fn test_gt_lt_gte_lte() { span: "0:127-139" span: "0:120-139" span: "0:9-139" - span: "0:9-140" + span: "0:0-139" "###) } @@ -1498,7 +1508,7 @@ join s=salaries (==id) span: "0:33-37" span: "0:16-38" span: "0:1-38" - span: "0:1-39" + span: "0:0-38" "###); } @@ -1537,7 +1547,7 @@ fn test_var_defs() { value: Ident: x span: "0:17-42" - span: "0:9-42" + span: "0:0-42" "###); assert_yaml_snapshot!(parse_single(r#" @@ -1551,7 +1561,7 @@ fn test_var_defs() { value: Ident: x span: "0:9-10" - span: "0:9-25" + span: "0:0-25" "###); assert_yaml_snapshot!(parse_single(r#" @@ -1564,7 +1574,7 @@ fn test_var_defs() { value: Ident: x span: "0:9-10" - span: "0:9-11" + span: "0:0-10" "###); } @@ -1587,7 +1597,7 @@ fn test_array() { Integer: 2 span: "0:21-22" span: "0:17-24" - span: "0:9-24" + span: "0:0-24" - VarDef: kind: Let name: a @@ -1600,7 +1610,7 @@ fn test_array() { String: hello span: "0:49-56" span: "0:41-57" - span: "0:33-57" + span: "0:24-57" "###); } @@ -1635,7 +1645,7 @@ fn test_annotation() { named_params: [] generic_type_params: [] span: "0:49-61" - span: "0:9-61" + span: "0:0-61" annotations: - expr: Tuple: @@ -1647,7 +1657,8 @@ fn test_annotation() { "###); parse_single( r#" - @{binding_strength=1} let add = a b -> a + b + @{binding_strength=1} + let add = a b -> a + b "#, ) .unwrap(); @@ -1751,7 +1762,7 @@ fn test_target() { span: "0:72-77" span: "0:65-77" span: "0:45-77" - span: "0:45-78" + span: "0:34-77" "###); } @@ -1777,7 +1788,7 @@ fn test_module() { Literal: Integer: 1 span: "0:50-51" - span: "0:38-51" + span: "0:25-51" - VarDef: kind: Let name: man @@ -1789,8 +1800,8 @@ fn test_module() { field: Name: world span: "0:74-86" - span: "0:64-86" - span: "0:11-98" + span: "0:51-86" + span: "0:0-98" "###); } @@ -1804,3 +1815,133 @@ fn test_number() { ) .is_err()); } + +#[test] +fn doc_comment() { + use insta::assert_yaml_snapshot; + + assert_yaml_snapshot!(parse_single(r###" + from artists + derive x = 5 + "###).unwrap(), @r###" + --- + - VarDef: + kind: Main + name: main + value: + Pipeline: + exprs: + - FuncCall: + name: + Ident: from + span: "0:5-9" + args: + - Ident: artists + span: "0:10-17" + span: "0:5-17" + - FuncCall: + name: + Ident: derive + span: "0:22-28" + args: + - Literal: + Integer: 5 + span: "0:33-34" + alias: x + span: "0:22-34" + span: "0:5-34" + span: "0:0-34" + "###); + + assert_yaml_snapshot!(parse_single(r###" + from artists + + #! This is a doc comment + + derive x = 5 + "###).unwrap(), @r###" + --- + - VarDef: + kind: Main + name: main + value: + FuncCall: + name: + Ident: from + span: "0:5-9" + args: + - Ident: artists + span: "0:10-17" + span: "0:5-17" + span: "0:0-17" + - VarDef: + kind: Main + name: main + value: + FuncCall: + name: + Ident: derive + span: "0:53-59" + args: + - Literal: + Integer: 5 + span: "0:64-65" + alias: x + span: "0:53-65" + span: "0:47-65" + doc_comment: " This is a doc comment" + "###); + + assert_yaml_snapshot!(parse_single(r###" + #! This is a doc comment + from artists + derive x = 5 + "###).unwrap(), @r###" + --- + - VarDef: + kind: Main + name: main + value: + Pipeline: + exprs: + - FuncCall: + name: + Ident: from + span: "0:34-38" + args: + - Ident: artists + span: "0:39-46" + span: "0:34-46" + - FuncCall: + name: + Ident: derive + span: "0:51-57" + args: + - Literal: + Integer: 5 + span: "0:62-63" + alias: x + span: "0:51-63" + span: "0:34-63" + span: "0:29-63" + doc_comment: " This is a doc comment" + "###); + + assert_debug_snapshot!(parse_single(r###" + from artists #! This is a doc comment + "###).unwrap_err(), @r###" + [ + Error { + kind: Error, + span: Some( + 0:18-42, + ), + reason: Simple( + "unexpected #! This is a doc comment\n", + ), + hints: [], + code: None, + }, + ] + "###); +} diff --git a/prqlc/prqlc/src/semantic/ast_expand.rs b/prqlc/prqlc/src/semantic/ast_expand.rs index c702af614a4d..8394a41fdbba 100644 --- a/prqlc/prqlc/src/semantic/ast_expand.rs +++ b/prqlc/prqlc/src/semantic/ast_expand.rs @@ -304,6 +304,7 @@ pub fn restrict_expr(expr: pl::Expr) -> pr::Expr { kind: restrict_expr_kind(expr.kind), span: expr.span, alias: expr.alias, + doc_comment: None, } } @@ -467,6 +468,7 @@ fn restrict_stmt(stmt: pl::Stmt) -> pr::Stmt { .into_iter() .map(restrict_annotation) .collect(), + doc_comment: None, } } diff --git a/prqlc/prqlc/tests/integration/bad_error_messages.rs b/prqlc/prqlc/tests/integration/bad_error_messages.rs index 9f4b25bf2019..25e89ce05c3f 100644 --- a/prqlc/prqlc/tests/integration/bad_error_messages.rs +++ b/prqlc/prqlc/tests/integration/bad_error_messages.rs @@ -220,11 +220,12 @@ fn just_std() { std "###).unwrap_err(), @r###" Error: - ╭─[:2:5] + ╭─[:1:1] │ - 2 │ std - │ ──┬─ - │ ╰─── internal compiler error; tracked at https://github.com/PRQL/prql/issues/4474 + 1 │ ╭─▶ + 2 │ ├─▶ std + │ │ + │ ╰───────────── internal compiler error; tracked at https://github.com/PRQL/prql/issues/4474 ───╯ "###); } diff --git a/prqlc/prqlc/tests/integration/error_messages.rs b/prqlc/prqlc/tests/integration/error_messages.rs index fdc44a0983a1..ee69ca0666bf 100644 --- a/prqlc/prqlc/tests/integration/error_messages.rs +++ b/prqlc/prqlc/tests/integration/error_messages.rs @@ -98,7 +98,7 @@ fn test_errors() { │ 1 │ Answer: T-H-A-T! │ ┬ - │ ╰── unexpected : while parsing function call + │ ╰── unexpected : ───╯ "###); } diff --git a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__aggregation.snap b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__aggregation.snap index feb3f0fbad2f..bb10ce1c8881 100644 --- a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__aggregation.snap +++ b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__aggregation.snap @@ -286,4 +286,4 @@ ast: span: 1:178-243 span: 1:168-243 span: 1:102-243 - span: 1:102-244 + span: 1:0-243 diff --git a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__arithmetic.snap b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__arithmetic.snap index 9c5a750c0f08..b4f798314b68 100644 --- a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__arithmetic.snap +++ b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__arithmetic.snap @@ -1277,4 +1277,4 @@ ast: span: 1:830-832 span: 1:825-832 span: 1:13-832 - span: 1:13-833 + span: 1:0-832 diff --git a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__cast.snap b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__cast.snap index 310465f90e8a..a5f28ab5572d 100644 --- a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__cast.snap +++ b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__cast.snap @@ -209,4 +209,4 @@ ast: span: 1:103-105 span: 1:98-105 span: 1:13-105 - span: 1:13-106 + span: 1:0-105 diff --git a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__constants_only.snap b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__constants_only.snap index df827a1fedcf..0ec1fbdecd0d 100644 --- a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__constants_only.snap +++ b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__constants_only.snap @@ -192,4 +192,4 @@ ast: alias: d span: 1:52-65 span: 1:0-65 - span: 1:0-66 + span: 1:0-65 diff --git a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__date_to_text.snap b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__date_to_text.snap index 955e7d60a22b..322da4de0e44 100644 --- a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__date_to_text.snap +++ b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__date_to_text.snap @@ -627,4 +627,4 @@ ast: span: 1:86-718 span: 1:79-718 span: 1:57-718 - span: 1:57-719 + span: 1:0-718 diff --git a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__distinct.snap b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__distinct.snap index 60c1240ce602..37c8167916d4 100644 --- a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__distinct.snap +++ b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__distinct.snap @@ -228,4 +228,4 @@ ast: span: 1:88-90 span: 1:77-90 span: 1:13-90 - span: 1:13-91 + span: 1:0-90 diff --git a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__distinct_on.snap b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__distinct_on.snap index be7a54a80889..c3b19d9668db 100644 --- a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__distinct_on.snap +++ b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__distinct_on.snap @@ -293,4 +293,4 @@ ast: span: 1:133-159 span: 1:128-159 span: 1:13-159 - span: 1:13-160 + span: 1:0-159 diff --git a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__genre_counts.snap b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__genre_counts.snap index 3d2bdc3a0345..24159d7d24df 100644 --- a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__genre_counts.snap +++ b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__genre_counts.snap @@ -125,7 +125,7 @@ ast: span: 1:167-183 span: 1:157-183 span: 1:135-185 - span: 1:117-185 + span: 1:0-185 - VarDef: kind: Main name: main @@ -170,4 +170,4 @@ ast: alias: a span: 1:217-230 span: 1:187-230 - span: 1:187-231 + span: 1:185-230 diff --git a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__group_all.snap b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__group_all.snap index 13ab542b8168..5149c491e3af 100644 --- a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__group_all.snap +++ b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__group_all.snap @@ -339,4 +339,4 @@ ast: span: 1:152-160 span: 1:147-160 span: 1:13-160 - span: 1:13-161 + span: 1:0-160 diff --git a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__group_sort.snap b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__group_sort.snap index 7331f875ccb6..16722f0bae96 100644 --- a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__group_sort.snap +++ b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__group_sort.snap @@ -325,4 +325,4 @@ ast: span: 1:136-150 span: 1:129-150 span: 1:13-150 - span: 1:13-151 + span: 1:0-150 diff --git a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__group_sort_limit_take.snap b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__group_sort_limit_take.snap index c8e9c4bc4627..d8e94bf276d7 100644 --- a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__group_sort_limit_take.snap +++ b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__group_sort_limit_take.snap @@ -362,7 +362,7 @@ ast: Integer: 3 span: 1:168-169 span: 1:163-169 - span: 1:140-169 + span: 1:137-169 span: 1:119-171 - FuncCall: name: @@ -411,4 +411,4 @@ ast: span: 1:230-251 span: 1:225-251 span: 1:76-251 - span: 1:76-252 + span: 1:0-251 diff --git a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__invoice_totals.snap b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__invoice_totals.snap index d763b64fe62f..dadcbbb337cb 100644 --- a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__invoice_totals.snap +++ b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__invoice_totals.snap @@ -871,7 +871,7 @@ ast: alias: total_price span: 1:338-466 span: 1:328-466 - span: 1:281-466 + span: 1:276-466 span: 1:254-468 - FuncCall: name: @@ -920,7 +920,7 @@ ast: Boolean: true span: 1:521-525 span: 1:504-592 - span: 1:488-592 + span: 1:483-592 span: 1:469-594 - FuncCall: name: @@ -984,4 +984,5 @@ ast: span: 1:789-791 span: 1:784-791 span: 1:131-791 - span: 1:131-792 + span: 1:130-791 + doc_comment: ' Calculate a number of metrics about the sales of tracks in each city.' diff --git a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__loop_01.snap b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__loop_01.snap index 8a0143ae52e8..1436d51ee9d2 100644 --- a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__loop_01.snap +++ b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__loop_01.snap @@ -363,4 +363,4 @@ ast: span: 1:255-256 span: 1:250-256 span: 1:162-256 - span: 1:162-257 + span: 1:0-256 diff --git a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__math_module.snap b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__math_module.snap index 49c84b3bf375..7b92c56f9b1d 100644 --- a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__math_module.snap +++ b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__math_module.snap @@ -945,4 +945,4 @@ ast: span: 1:110-839 span: 1:103-839 span: 1:82-839 - span: 1:82-840 + span: 1:0-839 diff --git a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__pipelines.snap b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__pipelines.snap index 705569b7ab1d..77e89cb74ca6 100644 --- a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__pipelines.snap +++ b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__pipelines.snap @@ -342,4 +342,4 @@ ast: span: 1:281-297 span: 1:274-297 span: 1:166-297 - span: 1:166-298 + span: 1:0-297 diff --git a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__read_csv.snap b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__read_csv.snap index e3b20518dfde..f12478b04ec2 100644 --- a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__read_csv.snap +++ b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__read_csv.snap @@ -74,4 +74,4 @@ ast: span: 1:97-110 span: 1:92-110 span: 1:43-110 - span: 1:43-111 + span: 1:0-110 diff --git a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__set_ops_remove.snap b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__set_ops_remove.snap index 5af44fc9bec6..0dd6dd7a607b 100644 --- a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__set_ops_remove.snap +++ b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__set_ops_remove.snap @@ -289,7 +289,7 @@ ast: named_params: [] generic_type_params: [] span: 1:28-79 - span: 1:13-79 + span: 1:0-79 - VarDef: kind: Main name: main @@ -339,4 +339,4 @@ ast: span: 1:244-245 span: 1:239-245 span: 1:81-245 - span: 1:81-246 + span: 1:79-245 diff --git a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__sort.snap b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__sort.snap index a1aa70338287..82f3ab247866 100644 --- a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__sort.snap +++ b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__sort.snap @@ -323,4 +323,4 @@ ast: span: 1:224-271 span: 1:217-271 span: 1:13-271 - span: 1:13-272 + span: 1:0-271 diff --git a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__switch.snap b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__switch.snap index c0fb2ecf4d47..957538b8f03c 100644 --- a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__switch.snap +++ b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__switch.snap @@ -234,4 +234,4 @@ ast: span: 1:252-254 span: 1:247-254 span: 1:89-254 - span: 1:89-255 + span: 1:0-254 diff --git a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__take.snap b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__take.snap index 8c02c5a85974..2b2a4492caf9 100644 --- a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__take.snap +++ b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__take.snap @@ -116,4 +116,4 @@ ast: span: 1:47-51 span: 1:42-51 span: 1:13-51 - span: 1:13-52 + span: 1:0-51 diff --git a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__text_module.snap b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__text_module.snap index 69bf68a2073c..b3cf60d07916 100644 --- a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__text_module.snap +++ b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__text_module.snap @@ -705,4 +705,4 @@ ast: span: 1:484-588 span: 1:477-588 span: 1:113-588 - span: 1:113-589 + span: 1:0-588 diff --git a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__window.snap b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__window.snap index 999eb235b48a..8c6cc9a41d7e 100644 --- a/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__window.snap +++ b/prqlc/prqlc/tests/integration/snapshots/integration__queries__debug_lineage__window.snap @@ -453,7 +453,7 @@ ast: Integer: 10 span: 1:914-916 span: 1:909-916 - span: 1:793-916 + span: 1:790-916 span: 1:774-918 - FuncCall: name: @@ -502,4 +502,4 @@ ast: span: 1:1006-1020 span: 1:999-1020 span: 1:762-1020 - span: 1:762-1021 + span: 1:0-1020