From fd22b511830d880c3a4b1173a30f8dcf21157418 Mon Sep 17 00:00:00 2001 From: Sayan Nandan Date: Tue, 10 Jan 2023 07:56:46 -0800 Subject: [PATCH] Use `State` for all other DDL statements --- server/src/engine/ql/ast.rs | 139 ++++++++++++++++++++--------- server/src/engine/ql/ddl.rs | 84 +++++++++-------- server/src/engine/ql/dml/delete.rs | 14 +-- server/src/engine/ql/dml/insert.rs | 4 +- server/src/engine/ql/dml/mod.rs | 40 +-------- server/src/engine/ql/dml/select.rs | 4 +- server/src/engine/ql/dml/update.rs | 4 +- 7 files changed, 158 insertions(+), 131 deletions(-) diff --git a/server/src/engine/ql/ast.rs b/server/src/engine/ql/ast.rs index 82eae2f2..c1acec59 100644 --- a/server/src/engine/ql/ast.rs +++ b/server/src/engine/ql/ast.rs @@ -30,7 +30,10 @@ use { lexer::{LitIR, Slice, Token}, schema, LangError, LangResult, }, - crate::{engine::memory::DataType, util::compiler}, + crate::{ + engine::memory::DataType, + util::{compiler, MaybeInit}, + }, core::cmp, }; @@ -230,6 +233,10 @@ impl<'a, Qd: QueryData<'a>> State<'a, Qd> { pub(crate) fn cursor(&self) -> usize { self.i } + #[inline(always)] + pub(crate) fn cursor_is_ident(&self) -> bool { + self.read().is_ident() + } } pub trait QueryData<'a> { @@ -428,6 +435,58 @@ impl<'a> Entity<'a> { }; Ok(r) } + #[inline(always)] + pub fn attempt_process_entity_result>( + state: &mut State<'a, Qd>, + ) -> LangResult { + let mut e = MaybeInit::uninit(); + Self::attempt_process_entity(state, &mut e); + if state.okay() { + unsafe { + // UNSAFE(@ohsayan): just checked if okay + Ok(e.assume_init()) + } + } else { + Err(LangError::UnexpectedToken) + } + } + #[inline(always)] + pub fn attempt_process_entity>( + state: &mut State<'a, Qd>, + d: &mut MaybeInit>, + ) { + let tok = state.current(); + let is_full = Entity::tokens_with_full(tok); + let is_single = Entity::tokens_with_single(tok); + unsafe { + if is_full { + state.cursor_ahead_by(3); + *d = MaybeInit::new(Entity::full_entity_from_slice(tok)); + } else if is_single { + state.cursor_ahead(); + *d = MaybeInit::new(Entity::single_entity_from_slice(tok)); + } + } + state.poison_if_not(is_full | is_single); + } + pub fn parse_entity>( + state: &mut State<'a, Qd>, + d: &mut MaybeInit>, + ) { + let tok = state.current(); + let is_full = tok[0].is_ident() && tok[1] == Token![.] && tok[2].is_ident(); + let is_single = tok[0].is_ident(); + unsafe { + if is_full { + state.cursor_ahead_by(3); + *d = MaybeInit::new(Entity::full_entity_from_slice(tok)); + } else if is_single { + state.cursor_ahead(); + *d = MaybeInit::new(Entity::single_entity_from_slice(tok)); + } + } + state.poison_if_not(is_full | is_single); + } } #[cfg_attr(test, derive(Debug, PartialEq))] @@ -473,54 +532,46 @@ pub enum Statement<'a> { } pub fn compile<'a, Qd: QueryData<'a>>(tok: &'a [Token], d: Qd) -> LangResult> { - let mut i = 0; if compiler::unlikely(tok.len() < 2) { return Err(LangError::UnexpectedEndofStatement); } - match tok[0] { + let mut state = State::new(tok, d); + match state.fw_read() { // DDL - Token![use] => Entity::parse_from_tokens(&tok[1..], &mut i).map(Statement::Use), - Token![drop] if tok.len() >= 3 => ddl::parse_drop(&tok[1..], &mut i), - Token::Ident(id) if id.eq_ignore_ascii_case(b"inspect") => { - ddl::parse_inspect(&tok[1..], &mut i) - } - ref stmt => { - let mut state = State::new(&tok[1..], d); - match stmt { - // DDL - Token![create] => { - match tok[1] { - Token![model] => schema::parse_model_from_tokens(&mut state) - .map(Statement::CreateModel), - Token![space] => schema::parse_space_from_tokens(&mut state) - .map(Statement::CreateSpace), - _ => compiler::cold_rerr(LangError::UnknownCreateStatement), - } - } - Token![alter] => match tok[1] { - Token![model] => { - schema::parse_alter_kind_from_tokens(&mut state).map(Statement::AlterModel) - } - Token![space] => { - schema::parse_alter_space_from_tokens(&mut state).map(Statement::AlterSpace) - } - _ => compiler::cold_rerr(LangError::UnknownAlterStatement), - }, - // DML - Token![insert] => { - dml::insert::InsertStatement::parse_insert(&mut state).map(Statement::Insert) - } - Token![select] => { - dml::select::SelectStatement::parse_select(&mut state).map(Statement::Select) - } - Token![update] => { - dml::update::UpdateStatement::parse_update(&mut state).map(Statement::Update) - } - Token![delete] => { - dml::delete::DeleteStatement::parse_delete(&mut state).map(Statement::Delete) - } - _ => compiler::cold_rerr(LangError::ExpectedStatement), + Token![use] => Entity::attempt_process_entity_result(&mut state).map(Statement::Use), + Token![create] => match state.fw_read() { + Token![model] => { + schema::parse_model_from_tokens(&mut state).map(Statement::CreateModel) + } + Token![space] => { + schema::parse_space_from_tokens(&mut state).map(Statement::CreateSpace) } + _ => compiler::cold_rerr(LangError::UnknownCreateStatement), + }, + Token![alter] => match state.fw_read() { + Token![model] => { + schema::parse_alter_kind_from_tokens(&mut state).map(Statement::AlterModel) + } + Token![space] => { + schema::parse_alter_space_from_tokens(&mut state).map(Statement::AlterSpace) + } + _ => compiler::cold_rerr(LangError::UnknownAlterStatement), + }, + Token![drop] if state.remaining() >= 2 => ddl::parse_drop(&mut state), + Token::Ident(id) if id.eq_ignore_ascii_case(b"inspect") => ddl::parse_inspect(&mut state), + // DML + Token![insert] => { + dml::insert::InsertStatement::parse_insert(&mut state).map(Statement::Insert) + } + Token![select] => { + dml::select::SelectStatement::parse_select(&mut state).map(Statement::Select) + } + Token![update] => { + dml::update::UpdateStatement::parse_update(&mut state).map(Statement::Update) + } + Token![delete] => { + dml::delete::DeleteStatement::parse_delete(&mut state).map(Statement::Delete) } + _ => compiler::cold_rerr(LangError::ExpectedStatement), } } diff --git a/server/src/engine/ql/ddl.rs b/server/src/engine/ql/ddl.rs index d984ecd0..895fab67 100644 --- a/server/src/engine/ql/ddl.rs +++ b/server/src/engine/ql/ddl.rs @@ -24,10 +24,15 @@ * */ -use super::{ - ast::{Entity, Statement}, - lexer::{Slice, Token}, - LangError, LangResult, +#[cfg(test)] +use super::ast::InplaceData; +use { + super::{ + ast::{Entity, QueryData, State, Statement}, + lexer::{Slice, Token}, + LangError, LangResult, + }, + crate::util::compiler, }; #[derive(Debug, PartialEq)] @@ -62,32 +67,31 @@ impl<'a> DropModel<'a> { /// ## Panic /// /// If token stream length is < 2 -pub(super) fn parse_drop<'a>(tok: &'a [Token], counter: &mut usize) -> LangResult> { - match tok[0] { +pub(super) fn parse_drop<'a, Qd: QueryData<'a>>( + state: &mut State<'a, Qd>, +) -> LangResult> { + match state.fw_read() { Token![model] => { // we have a model. now parse entity and see if we should force deletion - let mut i = 1; - let e = Entity::parse_from_tokens(&tok[1..], &mut i)?; - let force = i < tok.len() && tok[i] == Token::Ident(b"force"); - i += force as usize; - *counter += i; + let e = Entity::attempt_process_entity_result(state)?; + let force = state.cursor_rounded_eq(Token::Ident(b"force")); + state.cursor_ahead_if(force); // if we've exhausted the stream, we're good to go (either `force`, or nothing) - if tok.len() == i { + if state.exhausted() { return Ok(Statement::DropModel(DropModel::new(e, force))); } } - Token![space] if tok[1].is_ident() => { - let mut i = 2; // (`space` and space name) - // should we force drop? - let force = i < tok.len() && tok[i] == Token::Ident(b"force"); - i += force as usize; - *counter += i; + Token![space] if state.cursor_is_ident() => { + let ident = state.fw_read(); + // should we force drop? + let force = state.cursor_rounded_eq(Token::Ident(b"force")); + state.cursor_ahead_if(force); // either `force` or nothing - if tok.len() == i { + if state.exhausted() { return Ok(Statement::DropSpace(DropSpace::new( unsafe { // UNSAFE(@ohsayan): Safe because the match predicate ensures that tok[1] is indeed an ident - extract!(tok[1], Token::Ident(ref space) => *space) + extract!(ident, Token::Ident(ref space) => *space) }, force, ))); @@ -100,41 +104,49 @@ pub(super) fn parse_drop<'a>(tok: &'a [Token], counter: &mut usize) -> LangResul #[cfg(test)] pub(super) fn parse_drop_full<'a>(tok: &'a [Token]) -> LangResult> { - let mut i = 0; - let r = self::parse_drop(tok, &mut i); - assert_full_tt!(i, tok.len()); + let mut state = State::new(tok, InplaceData::new()); + let r = self::parse_drop(&mut state); + assert_full_tt!(state); r } -pub(super) fn parse_inspect<'a>(tok: &'a [Token], c: &mut usize) -> LangResult> { +pub(super) fn parse_inspect<'a, Qd: QueryData<'a>>( + state: &mut State<'a, Qd>, +) -> LangResult> { /* inpsect model inspect space inspect spaces + + min length -> ( | ) = 2 */ - let nxt = tok.get(0); - *c += nxt.is_some() as usize; - match nxt { - Some(Token![model]) => Entity::parse_from_tokens(&tok[1..], c).map(Statement::InspectModel), - Some(Token![space]) if tok.len() == 2 && tok[1].is_ident() => { - *c += 1; + if compiler::unlikely(state.remaining() < 1) { + return compiler::cold_rerr(LangError::UnexpectedEndofStatement); + } + + match state.fw_read() { + Token![model] => Entity::attempt_process_entity_result(state).map(Statement::InspectModel), + Token![space] if state.cursor_has_ident_rounded() => { Ok(Statement::InspectSpace(unsafe { // UNSAFE(@ohsayan): Safe because of the match predicate - extract!(tok[1], Token::Ident(ref space) => space) + extract!(state.fw_read(), Token::Ident(ref space) => space) })) } - Some(Token::Ident(id)) if id.eq_ignore_ascii_case(b"spaces") && tok.len() == 1 => { + Token::Ident(id) if id.eq_ignore_ascii_case(b"spaces") && state.exhausted() => { Ok(Statement::InspectSpaces) } - _ => Err(LangError::ExpectedStatement), + _ => { + state.cursor_back(); + Err(LangError::ExpectedStatement) + } } } #[cfg(test)] pub(super) fn parse_inspect_full<'a>(tok: &'a [Token]) -> LangResult> { - let mut i = 0; - let r = self::parse_inspect(tok, &mut i); - assert_full_tt!(i, tok.len()); + let mut state = State::new(tok, InplaceData::new()); + let r = self::parse_inspect(&mut state); + assert_full_tt!(state); r } diff --git a/server/src/engine/ql/dml/delete.rs b/server/src/engine/ql/dml/delete.rs index 3990324a..92989c96 100644 --- a/server/src/engine/ql/dml/delete.rs +++ b/server/src/engine/ql/dml/delete.rs @@ -24,13 +24,8 @@ * */ -#[cfg(test)] -use { - super::WhereClauseCollection, - crate::engine::ql::{ast::InplaceData, lexer::Token}, -}; use { - super::{parse_entity, WhereClause}, + super::WhereClause, crate::{ engine::ql::{ ast::{Entity, QueryData, State}, @@ -39,6 +34,11 @@ use { util::{compiler, MaybeInit}, }, }; +#[cfg(test)] +use { + super::WhereClauseCollection, + crate::engine::ql::{ast::InplaceData, lexer::Token}, +}; /* Impls for delete @@ -78,7 +78,7 @@ impl<'a> DeleteStatement<'a> { state.poison_if_not(state.cursor_eq(Token![from])); state.cursor_ahead(); // ignore errors (if any) let mut entity = MaybeInit::uninit(); - parse_entity(state, &mut entity); + Entity::parse_entity(state, &mut entity); // where + clauses state.poison_if_not(state.cursor_eq(Token![where])); state.cursor_ahead(); // ignore errors diff --git a/server/src/engine/ql/dml/insert.rs b/server/src/engine/ql/dml/insert.rs index 54c54315..4852afc4 100644 --- a/server/src/engine/ql/dml/insert.rs +++ b/server/src/engine/ql/dml/insert.rs @@ -27,7 +27,7 @@ #[cfg(test)] use crate::engine::ql::ast::InplaceData; use { - super::{parse_entity, read_ident}, + super::read_ident, crate::{ engine::{ memory::DataType, @@ -392,7 +392,7 @@ impl<'a> InsertStatement<'a> { // entity let mut entity = MaybeInit::uninit(); - parse_entity(state, &mut entity); + Entity::parse_entity(state, &mut entity); let mut data = None; match state.fw_read() { Token![() open] if state.not_exhausted() => { diff --git a/server/src/engine/ql/dml/mod.rs b/server/src/engine/ql/dml/mod.rs index 89a5082d..65c9c918 100644 --- a/server/src/engine/ql/dml/mod.rs +++ b/server/src/engine/ql/dml/mod.rs @@ -38,10 +38,10 @@ pub mod update; use super::ast::InplaceData; use { super::{ - ast::{Entity, QueryData, State}, + ast::{QueryData, State}, lexer::{LitIR, Token}, }, - crate::util::{compiler, MaybeInit}, + crate::util::compiler, std::collections::HashMap, }; @@ -59,42 +59,6 @@ fn u(b: bool) -> u8 { Misc */ -#[inline(always)] -fn attempt_process_entity<'a, Qd: QueryData<'a>>( - state: &mut State<'a, Qd>, - d: &mut MaybeInit>, -) { - let tok = state.current(); - let is_full = Entity::tokens_with_full(tok); - let is_single = Entity::tokens_with_single(tok); - unsafe { - if is_full { - state.cursor_ahead_by(3); - *d = MaybeInit::new(Entity::full_entity_from_slice(tok)); - } else if is_single { - state.cursor_ahead(); - *d = MaybeInit::new(Entity::single_entity_from_slice(tok)); - } - } - state.poison_if_not(is_full | is_single); -} - -fn parse_entity<'a, Qd: QueryData<'a>>(state: &mut State<'a, Qd>, d: &mut MaybeInit>) { - let tok = state.current(); - let is_full = tok[0].is_ident() && tok[1] == Token![.] && tok[2].is_ident(); - let is_single = tok[0].is_ident(); - unsafe { - if is_full { - state.cursor_ahead_by(3); - *d = MaybeInit::new(Entity::full_entity_from_slice(tok)); - } else if is_single { - state.cursor_ahead(); - *d = MaybeInit::new(Entity::single_entity_from_slice(tok)); - } - } - state.poison_if_not(is_full | is_single); -} - /* Contexts */ diff --git a/server/src/engine/ql/dml/select.rs b/server/src/engine/ql/dml/select.rs index 9f9d2c81..a538b3c1 100644 --- a/server/src/engine/ql/dml/select.rs +++ b/server/src/engine/ql/dml/select.rs @@ -27,7 +27,7 @@ #[cfg(test)] use crate::engine::ql::ast::InplaceData; use { - super::{attempt_process_entity, WhereClause, WhereClauseCollection}, + super::{WhereClause, WhereClauseCollection}, crate::{ engine::ql::{ ast::{Entity, QueryData, State}, @@ -122,7 +122,7 @@ impl<'a> SelectStatement<'a> { state.poison_if_not(state.cursor_eq(Token![from])); state.cursor_ahead(); // ignore errors let mut entity = MaybeInit::uninit(); - attempt_process_entity(state, &mut entity); + Entity::attempt_process_entity(state, &mut entity); let mut clauses = <_ as Default>::default(); if state.cursor_rounded_eq(Token![where]) { state.cursor_ahead(); diff --git a/server/src/engine/ql/dml/update.rs b/server/src/engine/ql/dml/update.rs index 5cd0f032..6f0f7b05 100644 --- a/server/src/engine/ql/dml/update.rs +++ b/server/src/engine/ql/dml/update.rs @@ -30,7 +30,7 @@ use { crate::engine::ql::{ast::InplaceData, lexer::Token}, }; use { - super::{parse_entity, read_ident, u, WhereClause}, + super::{read_ident, u, WhereClause}, crate::{ engine::ql::{ ast::{Entity, QueryData, State}, @@ -188,7 +188,7 @@ impl<'a> UpdateStatement<'a> { } // parse entity let mut entity = MaybeInit::uninit(); - parse_entity(state, &mut entity); + Entity::parse_entity(state, &mut entity); if !(state.has_remaining(6)) { unsafe { // UNSAFE(@ohsayan): Obvious from above, max 3 fw