Fix export generating unparsable code with the new parser (#3351)

This commit is contained in:
Mees Delzenne 2024-03-12 16:43:56 +01:00 committed by GitHub
parent 2fe398f5b4
commit 3c92765fad
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 99 additions and 3 deletions

View file

@ -89,12 +89,20 @@ pub fn escape_key(s: &str) -> Cow<'_, str> {
#[inline] #[inline]
/// Escapes an id if necessary /// Escapes an id if necessary
pub fn escape_rid(s: &str) -> Cow<'_, str> { pub fn escape_rid(s: &str) -> Cow<'_, str> {
#[cfg(feature = "experimental-parser")]
if let Some(x) = escape_reserved_keyword(s) {
return Cow::Owned(x);
}
escape_numeric(s, BRACKETL, BRACKETR, BRACKET_ESC) escape_numeric(s, BRACKETL, BRACKETR, BRACKET_ESC)
} }
#[inline] #[inline]
/// Escapes an ident if necessary /// Escapes an ident if necessary
pub fn escape_ident(s: &str) -> Cow<'_, str> { pub fn escape_ident(s: &str) -> Cow<'_, str> {
#[cfg(feature = "experimental-parser")]
if let Some(x) = escape_reserved_keyword(s) {
return Cow::Owned(x);
}
escape_numeric(s, BACKTICK, BACKTICK, BACKTICK_ESC) escape_numeric(s, BACKTICK, BACKTICK, BACKTICK_ESC)
} }
@ -136,6 +144,11 @@ pub fn escape_numeric<'a>(s: &'a str, l: char, r: char, e: &str) -> Cow<'a, str>
} }
} }
#[cfg(feature = "experimental-parser")]
pub fn escape_reserved_keyword(s: &str) -> Option<String> {
crate::syn::v2::could_be_reserved_keyword(s).then(|| format!("`{}`", s))
}
#[cfg(feature = "experimental-parser")] #[cfg(feature = "experimental-parser")]
#[inline] #[inline]
pub fn escape_numeric<'a>(s: &'a str, l: char, r: char, e: &str) -> Cow<'a, str> { pub fn escape_numeric<'a>(s: &'a str, l: char, r: char, e: &str) -> Cow<'a, str> {

View file

@ -114,6 +114,6 @@ impl Param {
impl fmt::Display for Param { impl fmt::Display for Param {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "${}", &self.0) write!(f, "${}", &self.0 .0)
} }
} }

View file

@ -3,9 +3,54 @@ use crate::{
sql::{language::Language, Algorithm}, sql::{language::Language, Algorithm},
syn::v2::token::{DistanceKind, Keyword, TokenKind}, syn::v2::token::{DistanceKind, Keyword, TokenKind},
}; };
use phf::phf_map; use phf::{phf_map, phf_set};
use unicase::UniCase; use unicase::UniCase;
/// A set of keywords which might in some contexts are dissallowed as an identifier.
pub static RESERVED_KEYWORD: phf::Set<UniCase<&'static str>> = phf_set! {
UniCase::ascii("ANALYZE"),
UniCase::ascii("BEGIN"),
UniCase::ascii("BREAK"),
UniCase::ascii("CANCEL"),
UniCase::ascii("COMMIT"),
UniCase::ascii("CONTINUE"),
UniCase::ascii("CREATE"),
UniCase::ascii("DEFINE"),
UniCase::ascii("FOR"),
UniCase::ascii("IF"),
UniCase::ascii("INFO"),
UniCase::ascii("INSERT"),
UniCase::ascii("KILL"),
UniCase::ascii("LIVE"),
UniCase::ascii("OPTION"),
UniCase::ascii("RETURN"),
UniCase::ascii("RELATE"),
UniCase::ascii("REMOVE"),
UniCase::ascii("SELECT"),
UniCase::ascii("LET"),
UniCase::ascii("SHOW"),
UniCase::ascii("SLEEP"),
UniCase::ascii("THROW"),
UniCase::ascii("UPDATE"),
UniCase::ascii("USE"),
UniCase::ascii("DIFF"),
UniCase::ascii("RAND"),
UniCase::ascii("NONE"),
UniCase::ascii("NULL"),
UniCase::ascii("AFTER"),
UniCase::ascii("BEFORE"),
UniCase::ascii("VALUE"),
UniCase::ascii("BY"),
UniCase::ascii("ALL"),
UniCase::ascii("TRUE"),
UniCase::ascii("FALSE"),
UniCase::ascii("WHERE"),
};
pub fn could_be_reserved(s: &str) -> bool {
RESERVED_KEYWORD.contains(&UniCase::ascii(s))
}
/// A map for mapping keyword strings to a tokenkind, /// A map for mapping keyword strings to a tokenkind,
pub(crate) static KEYWORDS: phf::Map<UniCase<&'static str>, TokenKind> = phf_map! { pub(crate) static KEYWORDS: phf::Map<UniCase<&'static str>, TokenKind> = phf_map! {
// Keywords // Keywords

View file

@ -10,7 +10,7 @@ mod datetime;
mod duration; mod duration;
mod ident; mod ident;
mod js; mod js;
mod keywords; pub mod keywords;
mod number; mod number;
mod reader; mod reader;
mod strand; mod strand;

View file

@ -15,6 +15,11 @@ mod test;
use lexer::Lexer; use lexer::Lexer;
use parser::{ParseError, ParseErrorKind, Parser}; use parser::{ParseError, ParseErrorKind, Parser};
/// Takes a string and returns if it could be a reserved keyword in certain contexts.
pub fn could_be_reserved_keyword(s: &str) -> bool {
lexer::keywords::could_be_reserved(s)
}
/// Parses a SurrealQL [`Query`] /// Parses a SurrealQL [`Query`]
/// ///
/// During query parsing, the total depth of calls to parse values (including arrays, expressions, /// During query parsing, the total depth of calls to parse values (including arrays, expressions,

View file

@ -345,6 +345,17 @@ async fn define_statement_event() -> Result<(), Error> {
assert!(tmp.is_ok()); assert!(tmp.is_ok());
// //
let tmp = res.remove(0).result?; let tmp = res.remove(0).result?;
#[cfg(feature = "parser2")]
let val = Value::parse(
"{
events: { test: 'DEFINE EVENT test ON user WHEN true THEN (CREATE activity SET user = $this, `value` = $after.email, action = $event)' },
fields: {},
tables: {},
indexes: {},
lives: {},
}",
);
#[cfg(not(feature = "parser2"))]
let val = Value::parse( let val = Value::parse(
"{ "{
events: { test: 'DEFINE EVENT test ON user WHEN true THEN (CREATE activity SET user = $this, value = $after.email, action = $event)' }, events: { test: 'DEFINE EVENT test ON user WHEN true THEN (CREATE activity SET user = $this, value = $after.email, action = $event)' },
@ -403,6 +414,17 @@ async fn define_statement_event_when_event() -> Result<(), Error> {
assert!(tmp.is_ok()); assert!(tmp.is_ok());
// //
let tmp = res.remove(0).result?; let tmp = res.remove(0).result?;
#[cfg(feature = "parser2")]
let val = Value::parse(
r#"{
events: { test: "DEFINE EVENT test ON user WHEN $event = 'CREATE' THEN (CREATE activity SET user = $this, `value` = $after.email, action = $event)" },
fields: {},
tables: {},
indexes: {},
lives: {},
}"#,
);
#[cfg(not(feature = "parser2"))]
let val = Value::parse( let val = Value::parse(
r#"{ r#"{
events: { test: "DEFINE EVENT test ON user WHEN $event = 'CREATE' THEN (CREATE activity SET user = $this, value = $after.email, action = $event)" }, events: { test: "DEFINE EVENT test ON user WHEN $event = 'CREATE' THEN (CREATE activity SET user = $this, value = $after.email, action = $event)" },
@ -461,6 +483,17 @@ async fn define_statement_event_when_logic() -> Result<(), Error> {
assert!(tmp.is_ok()); assert!(tmp.is_ok());
// //
let tmp = res.remove(0).result?; let tmp = res.remove(0).result?;
#[cfg(feature = "parser2")]
let val = Value::parse(
"{
events: { test: 'DEFINE EVENT test ON user WHEN $before.email != $after.email THEN (CREATE activity SET user = $this, `value` = $after.email, action = $event)' },
fields: {},
tables: {},
indexes: {},
lives: {},
}",
);
#[cfg(not(feature = "parser2"))]
let val = Value::parse( let val = Value::parse(
"{ "{
events: { test: 'DEFINE EVENT test ON user WHEN $before.email != $after.email THEN (CREATE activity SET user = $this, value = $after.email, action = $event)' }, events: { test: 'DEFINE EVENT test ON user WHEN $before.email != $after.email THEN (CREATE activity SET user = $this, value = $after.email, action = $event)' },