From 52aef7ccc4b84d0ed7c8cf5310c164fa4fc89e4b Mon Sep 17 00:00:00 2001 From: Mees Delzenne Date: Wed, 18 Sep 2024 17:50:44 +0200 Subject: [PATCH] Fix fields being parsed as idioms. (#4819) --- core/src/syn/mod.rs | 4 +-- core/src/syn/parser/basic/mod.rs | 5 +-- core/src/syn/parser/mod.rs | 4 +-- core/src/syn/parser/stmt/define.rs | 18 +++++----- core/src/syn/parser/stmt/insert.rs | 2 +- core/src/syn/parser/stmt/mod.rs | 2 +- core/src/syn/parser/stmt/relate.rs | 8 +++++ core/src/syn/parser/test/mod.rs | 16 ++++++++- core/src/syn/parser/test/stmt.rs | 34 ++++++++---------- core/src/syn/parser/test/streaming.rs | 34 ++++++++---------- core/src/syn/parser/test/value.rs | 52 +++++++++++++-------------- core/src/syn/parser/thing.rs | 4 +-- core/src/syn/test.rs | 2 +- 13 files changed, 100 insertions(+), 85 deletions(-) diff --git a/core/src/syn/mod.rs b/core/src/syn/mod.rs index 76d79eb8..98ae39fc 100644 --- a/core/src/syn/mod.rs +++ b/core/src/syn/mod.rs @@ -64,7 +64,7 @@ pub fn value(input: &str) -> Result { .with_query_recursion_limit(*MAX_QUERY_PARSING_DEPTH as usize); let mut stack = Stack::new(); stack - .enter(|stk| parser.parse_value_table(stk)) + .enter(|stk| parser.parse_value_field(stk)) .finish() .and_then(|e| parser.assert_finished().map(|_| e)) .map_err(|e| e.render_on(input)) @@ -211,7 +211,7 @@ pub fn value_legacy_strand(input: &str) -> Result { let mut stack = Stack::new(); parser.allow_legacy_strand(true); stack - .enter(|stk| parser.parse_value_table(stk)) + .enter(|stk| parser.parse_value_field(stk)) .finish() .and_then(|e| parser.assert_finished().map(|_| e)) .map_err(|e| e.render_on(input)) diff --git a/core/src/syn/parser/basic/mod.rs b/core/src/syn/parser/basic/mod.rs index 1d1a2b88..bf63df17 100644 --- a/core/src/syn/parser/basic/mod.rs +++ b/core/src/syn/parser/basic/mod.rs @@ -188,6 +188,7 @@ impl Parser<'_> { #[cfg(test)] mod test { + use crate::sql::{Ident, Part}; #[test] fn identifiers() { @@ -206,8 +207,8 @@ mod test { assert_eq!( r, - sql::Query(sql::Statements(vec![sql::Statement::Value(sql::Value::Table( - sql::Table(ident.to_string()) + sql::Query(sql::Statements(vec![sql::Statement::Value(sql::Value::Idiom( + sql::Idiom(vec![Part::Field(Ident(ident.to_string()))]) ))])) ) } diff --git a/core/src/syn/parser/mod.rs b/core/src/syn/parser/mod.rs index cfe8cee9..73840ed3 100644 --- a/core/src/syn/parser/mod.rs +++ b/core/src/syn/parser/mod.rs @@ -134,7 +134,7 @@ impl<'a> Parser<'a> { last_span: Span::empty(), token_buffer: TokenBuffer::new(), glued_value: GluedValue::None, - table_as_field: false, + table_as_field: true, legacy_strands: false, flexible_record_id: true, object_recursion: 100, @@ -180,7 +180,7 @@ impl<'a> Parser<'a> { pub fn reset(&mut self) { self.last_span = Span::empty(); self.token_buffer.clear(); - self.table_as_field = false; + self.table_as_field = true; self.lexer.reset(); } diff --git a/core/src/syn/parser/stmt/define.rs b/core/src/syn/parser/stmt/define.rs index 7ceed31a..cad960fd 100644 --- a/core/src/syn/parser/stmt/define.rs +++ b/core/src/syn/parser/stmt/define.rs @@ -335,12 +335,12 @@ impl Parser<'_> { t!("SIGNUP") => { self.pop_peek(); ac.signup = - Some(stk.run(|stk| self.parse_value_table(stk)).await?); + Some(stk.run(|stk| self.parse_value_field(stk)).await?); } t!("SIGNIN") => { self.pop_peek(); ac.signin = - Some(stk.run(|stk| self.parse_value_table(stk)).await?); + Some(stk.run(|stk| self.parse_value_field(stk)).await?); } _ => break, } @@ -375,7 +375,7 @@ impl Parser<'_> { } t!("AUTHENTICATE") => { self.pop_peek(); - res.authenticate = Some(stk.run(|stk| self.parse_value_table(stk)).await?); + res.authenticate = Some(stk.run(|stk| self.parse_value_field(stk)).await?); } t!("DURATION") => { self.pop_peek(); @@ -581,11 +581,11 @@ impl Parser<'_> { } t!("SIGNUP") => { self.pop_peek(); - ac.signup = Some(stk.run(|stk| self.parse_value_table(stk)).await?); + ac.signup = Some(stk.run(|stk| self.parse_value_field(stk)).await?); } t!("SIGNIN") => { self.pop_peek(); - ac.signin = Some(stk.run(|stk| self.parse_value_table(stk)).await?); + ac.signin = Some(stk.run(|stk| self.parse_value_field(stk)).await?); } _ => break, } @@ -619,7 +619,7 @@ impl Parser<'_> { match self.peek_kind() { t!("VALUE") => { self.pop_peek(); - res.value = ctx.run(|ctx| self.parse_value_table(ctx)).await?; + res.value = ctx.run(|ctx| self.parse_value_field(ctx)).await?; } t!("COMMENT") => { self.pop_peek(); @@ -758,13 +758,13 @@ impl Parser<'_> { match self.peek_kind() { t!("WHEN") => { self.pop_peek(); - res.when = ctx.run(|ctx| self.parse_value_table(ctx)).await?; + res.when = ctx.run(|ctx| self.parse_value_field(ctx)).await?; } t!("THEN") => { self.pop_peek(); - res.then = Values(vec![ctx.run(|ctx| self.parse_value_table(ctx)).await?]); + res.then = Values(vec![ctx.run(|ctx| self.parse_value_field(ctx)).await?]); while self.eat(t!(",")) { - res.then.0.push(ctx.run(|ctx| self.parse_value_table(ctx)).await?) + res.then.0.push(ctx.run(|ctx| self.parse_value_field(ctx)).await?) } } t!("COMMENT") => { diff --git a/core/src/syn/parser/stmt/insert.rs b/core/src/syn/parser/stmt/insert.rs index 3f23c31b..253c2166 100644 --- a/core/src/syn/parser/stmt/insert.rs +++ b/core/src/syn/parser/stmt/insert.rs @@ -129,7 +129,7 @@ impl Parser<'_> { let mut values = Vec::new(); let start = expected!(self, t!("(")).span; loop { - values.push(self.parse_value_table(ctx).await?); + values.push(self.parse_value_field(ctx).await?); if !self.eat(t!(",")) { break; diff --git a/core/src/syn/parser/stmt/mod.rs b/core/src/syn/parser/stmt/mod.rs index 5e3a525d..bcba5003 100644 --- a/core/src/syn/parser/stmt/mod.rs +++ b/core/src/syn/parser/stmt/mod.rs @@ -214,7 +214,7 @@ impl Parser<'_> { } _ => { // TODO: Provide information about keywords. - let value = ctx.run(|ctx| self.parse_value_table(ctx)).await?; + let value = ctx.run(|ctx| self.parse_value_field(ctx)).await?; Ok(Self::refine_stmt_value(value)) } } diff --git a/core/src/syn/parser/stmt/relate.rs b/core/src/syn/parser/stmt/relate.rs index b0488730..b7837373 100644 --- a/core/src/syn/parser/stmt/relate.rs +++ b/core/src/syn/parser/stmt/relate.rs @@ -75,6 +75,14 @@ impl Parser<'_> { } } pub async fn parse_relate_value(&mut self, ctx: &mut Stk) -> ParseResult { + let old = self.table_as_field; + self.table_as_field = true; + let r = self.parse_relate_value_inner(ctx).await; + self.table_as_field = old; + r + } + + async fn parse_relate_value_inner(&mut self, ctx: &mut Stk) -> ParseResult { match self.peek_kind() { t!("[") => { let start = self.pop_peek().span; diff --git a/core/src/syn/parser/test/mod.rs b/core/src/syn/parser/test/mod.rs index 9c69db00..8eb24466 100644 --- a/core/src/syn/parser/test/mod.rs +++ b/core/src/syn/parser/test/mod.rs @@ -1,5 +1,5 @@ use crate::{ - sql::{self, Id, Statement, Thing, Value}, + sql::{self, Id, Ident, Idiom, Part, Query, Statement, Statements, Thing, Value}, syn::parser::mac::test_parse, }; @@ -83,6 +83,20 @@ fn query_object() { test_parse!(parse_query, src).inspect_err(|e| eprintln!("{}", e.render_on(src))).unwrap(); } +#[test] +fn ident_is_field() { + let src = r#"foo"#; + + let field = + test_parse!(parse_query, src).inspect_err(|e| eprintln!("{}", e.render_on(src))).unwrap(); + assert_eq!( + field, + Query(Statements(vec![Statement::Value(Value::Idiom(Idiom(vec![Part::Field(Ident( + "foo".to_string() + ))])))])) + ); +} + #[test] fn escaped_params_backtick() { test_parse!( diff --git a/core/src/syn/parser/test/stmt.rs b/core/src/syn/parser/test/stmt.rs index 85f55a8b..85c325a5 100644 --- a/core/src/syn/parser/test/stmt.rs +++ b/core/src/syn/parser/test/stmt.rs @@ -41,6 +41,10 @@ use crate::{ }; use chrono::{offset::TimeZone, NaiveDate, Offset, Utc}; +fn ident_field(name: &str) -> Value { + Value::Idiom(Idiom(vec![Part::Field(Ident(name.to_string()))])) +} + #[test] pub fn parse_analyze() { let res = test_parse!(parse_stmt, r#"ANALYZE INDEX b on a"#).unwrap(); @@ -205,7 +209,7 @@ fn parse_define_function() { (Ident("b".to_string()), Kind::Array(Box::new(Kind::Bool), Some(3))) ], block: Block(vec![Entry::Output(OutputStatement { - what: Value::Table(Table("a".to_string())), + what: ident_field("a"), fetch: None, })]), comment: Some(Strand("test".to_string())), @@ -1709,10 +1713,10 @@ fn parse_if() { res, Statement::Ifelse(IfelseStatement { exprs: vec![ - (Value::Table(Table("foo".to_owned())), Value::Table(Table("bar".to_owned()))), - (Value::Table(Table("faz".to_owned())), Value::Table(Table("baz".to_owned()))) + (ident_field("foo"), ident_field("bar")), + (ident_field("faz"), ident_field("baz")), ], - close: Some(Value::Table(Table("baq".to_owned()))) + close: Some(ident_field("baq")) }) ) } @@ -1726,21 +1730,15 @@ fn parse_if_block() { Statement::Ifelse(IfelseStatement { exprs: vec![ ( - Value::Table(Table("foo".to_owned())), - Value::Block(Box::new(Block(vec![Entry::Value(Value::Table(Table( - "bar".to_owned() - )),)]))), + ident_field("foo"), + Value::Block(Box::new(Block(vec![Entry::Value(ident_field("bar"))]))), ), ( - Value::Table(Table("faz".to_owned())), - Value::Block(Box::new(Block(vec![Entry::Value(Value::Table(Table( - "baz".to_owned() - )),)]))), + ident_field("faz"), + Value::Block(Box::new(Block(vec![Entry::Value(ident_field("baz"))]))), ) ], - close: Some(Value::Block(Box::new(Block(vec![Entry::Value(Value::Table(Table( - "baq".to_owned() - )))])))), + close: Some(Value::Block(Box::new(Block(vec![Entry::Value(ident_field("baq"))])))), }) ) } @@ -2193,10 +2191,8 @@ fn parse_return() { assert_eq!( res, Statement::Output(OutputStatement { - what: Value::Table(Table("RETRUN".to_owned())), - fetch: Some(Fetchs(vec![Fetch(Value::Idiom(Idiom(vec![Part::Field( - Ident("RETURN".to_owned()).to_owned() - )])))])), + what: ident_field("RETRUN"), + fetch: Some(Fetchs(vec![Fetch(ident_field("RETURN"))])) }), ) } diff --git a/core/src/syn/parser/test/streaming.rs b/core/src/syn/parser/test/streaming.rs index a33d2598..c550b80b 100644 --- a/core/src/syn/parser/test/streaming.rs +++ b/core/src/syn/parser/test/streaming.rs @@ -31,6 +31,10 @@ use crate::{ use chrono::{offset::TimeZone, NaiveDate, Offset, Utc}; use reblessive::Stack; +fn ident_field(name: &str) -> Value { + Value::Idiom(Idiom(vec![Part::Field(Ident(name.to_string()))])) +} + static SOURCE: &str = r#" ANALYZE INDEX b on a; BEGIN; @@ -192,7 +196,7 @@ fn statements() -> Vec { (Ident("b".to_string()), Kind::Array(Box::new(Kind::Bool), Some(3))), ], block: Block(vec![Entry::Output(OutputStatement { - what: Value::Table(Table("a".to_string())), + what: ident_field("a"), fetch: None, })]), comment: Some(Strand("test".to_string())), @@ -440,29 +444,23 @@ fn statements() -> Vec { }), Statement::Ifelse(IfelseStatement { exprs: vec![ - (Value::Table(Table("foo".to_owned())), Value::Table(Table("bar".to_owned()))), - (Value::Table(Table("faz".to_owned())), Value::Table(Table("baz".to_owned()))), + (ident_field("foo"), ident_field("bar")), + (ident_field("faz"), ident_field("baz")), ], - close: Some(Value::Table(Table("baq".to_owned()))), + close: Some(ident_field("baq")), }), Statement::Ifelse(IfelseStatement { exprs: vec![ ( - Value::Table(Table("foo".to_owned())), - Value::Block(Box::new(Block(vec![Entry::Value(Value::Table(Table( - "bar".to_owned(), - )))]))), + ident_field("foo"), + Value::Block(Box::new(Block(vec![Entry::Value(ident_field("bar"))]))), ), ( - Value::Table(Table("faz".to_owned())), - Value::Block(Box::new(Block(vec![Entry::Value(Value::Table(Table( - "baz".to_owned(), - )))]))), + ident_field("faz"), + Value::Block(Box::new(Block(vec![Entry::Value(ident_field("baz"))]))), ), ], - close: Some(Value::Block(Box::new(Block(vec![Entry::Value(Value::Table(Table( - "baq".to_owned(), - )))])))), + close: Some(Value::Block(Box::new(Block(vec![Entry::Value(ident_field("baq"))])))), }), Statement::Info(InfoStatement::Root(false)), Statement::Info(InfoStatement::Ns(false)), @@ -606,10 +604,8 @@ fn statements() -> Vec { id: Value::Uuid(Uuid(uuid::uuid!("e72bee20-f49b-11ec-b939-0242ac120002"))), }), Statement::Output(OutputStatement { - what: Value::Table(Table("RETRUN".to_owned())), - fetch: Some(Fetchs(vec![Fetch(Value::Idiom(Idiom(vec![Part::Field( - Ident("RETURN".to_owned()).to_owned(), - )])))])), + what: ident_field("RETRUN"), + fetch: Some(Fetchs(vec![Fetch(ident_field("RETURN"))])), }), Statement::Relate(RelateStatement { only: true, diff --git a/core/src/syn/parser/test/value.rs b/core/src/syn/parser/test/value.rs index 6dcc6ecd..976052ca 100644 --- a/core/src/syn/parser/test/value.rs +++ b/core/src/syn/parser/test/value.rs @@ -12,7 +12,7 @@ use crate::{ #[test] fn parse_index_expression() { - let value = test_parse!(parse_value_table, "a[1 + 1]").unwrap(); + let value = test_parse!(parse_value_field, "a[1 + 1]").unwrap(); let Value::Idiom(x) = value else { panic!("not the right value type"); }; @@ -29,7 +29,7 @@ fn parse_index_expression() { #[test] fn parse_coordinate() { - let coord = test_parse!(parse_value_table, "(1.88, -18.0)").unwrap(); + let coord = test_parse!(parse_value_field, "(1.88, -18.0)").unwrap(); let Value::Geometry(Geometry::Point(x)) = coord else { panic!("not the right value"); }; @@ -39,12 +39,12 @@ fn parse_coordinate() { #[test] fn parse_like_operator() { - test_parse!(parse_value_table, "a ~ b").unwrap(); + test_parse!(parse_value_field, "a ~ b").unwrap(); } #[test] fn parse_range_operator() { - test_parse!(parse_value_table, "1..2").unwrap(); + test_parse!(parse_value_field, "1..2").unwrap(); } #[test] @@ -116,7 +116,7 @@ fn parse_large_depth_record_id() { #[test] fn parse_recursive_record_string() { - let res = test_parse!(parse_value_table, r#" r"a:[r"b:{c: r"d:1"}"]" "#).unwrap(); + let res = test_parse!(parse_value_field, r#" r"a:[r"b:{c: r"d:1"}"]" "#).unwrap(); assert_eq!( res, Value::Thing(Thing { @@ -137,7 +137,7 @@ fn parse_recursive_record_string() { #[test] fn parse_record_string_2() { - let res = test_parse!(parse_value_table, r#" r'a:["foo"]' "#).unwrap(); + let res = test_parse!(parse_value_field, r#" r'a:["foo"]' "#).unwrap(); assert_eq!( res, Value::Thing(Thing { @@ -149,82 +149,82 @@ fn parse_record_string_2() { #[test] fn parse_i64() { - let res = test_parse!(parse_value_table, r#" -9223372036854775808 "#).unwrap(); + let res = test_parse!(parse_value_field, r#" -9223372036854775808 "#).unwrap(); assert_eq!(res, Value::Number(Number::Int(i64::MIN))); - let res = test_parse!(parse_value_table, r#" 9223372036854775807 "#).unwrap(); + let res = test_parse!(parse_value_field, r#" 9223372036854775807 "#).unwrap(); assert_eq!(res, Value::Number(Number::Int(i64::MAX))); } #[test] fn constant_lowercase() { - let out = test_parse!(parse_value_table, r#" math::pi "#).unwrap(); + let out = test_parse!(parse_value_field, r#" math::pi "#).unwrap(); assert_eq!(out, Value::Constant(Constant::MathPi)); - let out = test_parse!(parse_value_table, r#" math::inf "#).unwrap(); + let out = test_parse!(parse_value_field, r#" math::inf "#).unwrap(); assert_eq!(out, Value::Constant(Constant::MathInf)); - let out = test_parse!(parse_value_table, r#" math::neg_inf "#).unwrap(); + let out = test_parse!(parse_value_field, r#" math::neg_inf "#).unwrap(); assert_eq!(out, Value::Constant(Constant::MathNegInf)); - let out = test_parse!(parse_value_table, r#" time::epoch "#).unwrap(); + let out = test_parse!(parse_value_field, r#" time::epoch "#).unwrap(); assert_eq!(out, Value::Constant(Constant::TimeEpoch)); } #[test] fn constant_uppercase() { - let out = test_parse!(parse_value_table, r#" MATH::PI "#).unwrap(); + let out = test_parse!(parse_value_field, r#" MATH::PI "#).unwrap(); assert_eq!(out, Value::Constant(Constant::MathPi)); - let out = test_parse!(parse_value_table, r#" MATH::INF "#).unwrap(); + let out = test_parse!(parse_value_field, r#" MATH::INF "#).unwrap(); assert_eq!(out, Value::Constant(Constant::MathInf)); - let out = test_parse!(parse_value_table, r#" MATH::NEG_INF "#).unwrap(); + let out = test_parse!(parse_value_field, r#" MATH::NEG_INF "#).unwrap(); assert_eq!(out, Value::Constant(Constant::MathNegInf)); - let out = test_parse!(parse_value_table, r#" TIME::EPOCH "#).unwrap(); + let out = test_parse!(parse_value_field, r#" TIME::EPOCH "#).unwrap(); assert_eq!(out, Value::Constant(Constant::TimeEpoch)); } #[test] fn constant_mixedcase() { - let out = test_parse!(parse_value_table, r#" MaTh::Pi "#).unwrap(); + let out = test_parse!(parse_value_field, r#" MaTh::Pi "#).unwrap(); assert_eq!(out, Value::Constant(Constant::MathPi)); - let out = test_parse!(parse_value_table, r#" MaTh::Inf "#).unwrap(); + let out = test_parse!(parse_value_field, r#" MaTh::Inf "#).unwrap(); assert_eq!(out, Value::Constant(Constant::MathInf)); - let out = test_parse!(parse_value_table, r#" MaTh::Neg_Inf "#).unwrap(); + let out = test_parse!(parse_value_field, r#" MaTh::Neg_Inf "#).unwrap(); assert_eq!(out, Value::Constant(Constant::MathNegInf)); - let out = test_parse!(parse_value_table, r#" TiME::ePoCH "#).unwrap(); + let out = test_parse!(parse_value_field, r#" TiME::ePoCH "#).unwrap(); assert_eq!(out, Value::Constant(Constant::TimeEpoch)); } #[test] fn scientific_decimal() { - let res = test_parse!(parse_value_table, r#" 9.7e-7dec "#).unwrap(); + let res = test_parse!(parse_value_field, r#" 9.7e-7dec "#).unwrap(); assert!(matches!(res, Value::Number(Number::Decimal(_)))); assert_eq!(res.to_string(), "0.00000097dec") } #[test] fn scientific_number() { - let res = test_parse!(parse_value_table, r#" 9.7e-5"#).unwrap(); + let res = test_parse!(parse_value_field, r#" 9.7e-5"#).unwrap(); assert!(matches!(res, Value::Number(Number::Float(_)))); assert_eq!(res.to_string(), "0.000097f") } #[test] fn number_method() { - let res = test_parse!(parse_value_table, r#" 9.7e-5.sin()"#).unwrap(); + let res = test_parse!(parse_value_field, r#" 9.7e-5.sin()"#).unwrap(); let expected = Value::Idiom(Idiom(vec![ Part::Start(Value::Number(Number::Float(9.7e-5))), Part::Method("sin".to_string(), vec![]), ])); assert_eq!(res, expected); - let res = test_parse!(parse_value_table, r#" 1.sin()"#).unwrap(); + let res = test_parse!(parse_value_field, r#" 1.sin()"#).unwrap(); let expected = Value::Idiom(Idiom(vec![ Part::Start(Value::Number(Number::Int(1))), Part::Method("sin".to_string(), vec![]), @@ -234,10 +234,10 @@ fn number_method() { #[test] fn datetime_error() { - test_parse!(parse_value_table, r#" d"2001-01-01T01:01:01.9999999999" "#).unwrap_err(); + test_parse!(parse_value_field, r#" d"2001-01-01T01:01:01.9999999999" "#).unwrap_err(); } #[test] fn empty_string() { - test_parse!(parse_value_table, "").unwrap_err(); + test_parse!(parse_value_field, "").unwrap_err(); } diff --git a/core/src/syn/parser/thing.rs b/core/src/syn/parser/thing.rs index b6dfde5b..2a2ab188 100644 --- a/core/src/syn/parser/thing.rs +++ b/core/src/syn/parser/thing.rs @@ -125,7 +125,7 @@ impl Parser<'_> { pub(crate) async fn parse_range(&mut self, ctx: &mut Stk) -> ParseResult { // Check for beginning id let beg = if Self::kind_is_identifier(self.peek_whitespace().kind) { - let v = ctx.run(|ctx| self.parse_value_table(ctx)).await?; + let v = ctx.run(|ctx| self.parse_value_inherit(ctx)).await?; if self.eat_whitespace(t!(">")) { Bound::Excluded(v) @@ -142,7 +142,7 @@ impl Parser<'_> { // parse ending id. let end = if Self::kind_is_identifier(self.peek_whitespace().kind) { - let v = ctx.run(|ctx| self.parse_value_table(ctx)).await?; + let v = ctx.run(|ctx| self.parse_value_inherit(ctx)).await?; if inclusive { Bound::Included(v) } else { diff --git a/core/src/syn/test.rs b/core/src/syn/test.rs index f278d5f0..60066d88 100644 --- a/core/src/syn/test.rs +++ b/core/src/syn/test.rs @@ -69,7 +69,7 @@ impl Parse for Expression { let mut parser = Parser::new(val.as_bytes()); let mut stack = Stack::new(); let value = stack - .enter(|ctx| parser.parse_value_table(ctx)) + .enter(|ctx| parser.parse_value_field(ctx)) .finish() .map_err(|e| e.render_on(val)) .unwrap();