From 36a2b0162f383e371057d95de8052f44b242f27d Mon Sep 17 00:00:00 2001 From: Sayan Nandan Date: Thu, 22 Sep 2022 20:25:38 +0530 Subject: [PATCH] Enable creating spaces --- server/src/engine/ql/ast.rs | 10 +++- server/src/engine/ql/schema.rs | 102 ++++++++++++++++++++++++++------- 2 files changed, 88 insertions(+), 24 deletions(-) diff --git a/server/src/engine/ql/ast.rs b/server/src/engine/ql/ast.rs index 43c8cdea..ae63fb54 100644 --- a/server/src/engine/ql/ast.rs +++ b/server/src/engine/ql/ast.rs @@ -76,6 +76,7 @@ impl Entity { #[derive(Debug, PartialEq)] pub enum Statement { CreateModel(schema::Model), + CreateSpace(schema::Space), } pub struct Compiler<'a> { @@ -146,14 +147,19 @@ impl<'a> Compiler<'a> { fn c_model0(&mut self) -> Result { let model_name = match self.nxtok_opt() { Some(Token::Ident(model)) => unsafe { model.raw_clone() }, - _ => return Err(LangError::UnexpectedEndofStatement), + _ => return Err(LangError::UnexpectedToken), }; let model = schema::parse_schema(self, model_name)?; Ok(Statement::CreateModel(model)) } #[inline(always)] fn c_space0(&mut self) -> Result { - todo!() + let space_name = match self.nxtok_opt() { + Some(Token::Ident(space_name)) => unsafe { space_name.raw_clone() }, + _ => return Err(LangError::UnexpectedToken), + }; + let space = schema::parse_space(self, space_name)?; + Ok(Statement::CreateSpace(space)) } } diff --git a/server/src/engine/ql/schema.rs b/server/src/engine/ql/schema.rs index df4e95e3..dfba8fb0 100644 --- a/server/src/engine/ql/schema.rs +++ b/server/src/engine/ql/schema.rs @@ -145,6 +145,12 @@ pub struct Model { pub(super) props: Dict, } +#[derive(Debug, PartialEq)] +pub struct Space { + pub(super) space_name: Box, + pub(super) props: Dict, +} + /* Context-free dict */ @@ -269,33 +275,42 @@ pub struct TyMetaFoldResult { } impl TyMetaFoldResult { + #[inline(always)] const fn new() -> Self { Self { c: 0, b: [true, false], } } + #[inline(always)] fn incr(&mut self) { self.incr_by(1) } + #[inline(always)] fn incr_by(&mut self, by: usize) { self.c += by; } + #[inline(always)] fn set_fail(&mut self) { self.b[0] = false; } + #[inline(always)] fn set_has_more(&mut self) { self.b[1] = true; } + #[inline(always)] pub fn pos(&self) -> usize { self.c } + #[inline(always)] pub fn has_more(&self) -> bool { self.b[1] } + #[inline(always)] pub fn is_okay(&self) -> bool { self.b[0] } + #[inline(always)] fn record(&mut self, c: bool) { self.b[0] &= c; } @@ -631,40 +646,42 @@ pub(super) fn parse_schema_from_tokens( } // model properties - if i == l && okay { - // we've reached end of stream, so there's nothing more to parse - return Ok(( - Model { - model_name, - props: dict! {}, - fields, - }, - i, - )); - } else if !okay || tok[i] != Token::Keyword(Keyword::DdlMisc(DdlMiscKeyword::With)) { + if !okay { return Err(LangError::UnexpectedToken); } - // we have some more input, and it should be a dict of properties - i += 1; // +WITH + if l > i && tok[i] == Token::Keyword(Keyword::DdlMisc(DdlMiscKeyword::With)) { + // we have some more input, and it should be a dict of properties + i += 1; // +WITH - // great, parse the dict - let mut dict = Dict::new(); - let r = self::rfold_dict(DictFoldState::OB, &tok[i..], &mut dict); - i += (r & !HIBIT) as usize; + // great, parse the dict + let mut dict = Dict::new(); + let r = self::rfold_dict(DictFoldState::OB, &tok[i..], &mut dict); + i += (r & !HIBIT) as usize; - if r & HIBIT == HIBIT { - // sweet, so we got our dict + if r & HIBIT == HIBIT { + // sweet, so we got our dict + Ok(( + Model { + model_name, + props: dict, + fields, + }, + i, + )) + } else { + Err(LangError::UnexpectedToken) + } + } else { + // we've reached end of stream, so there's nothing more to parse Ok(( Model { model_name, - props: dict, + props: dict! {}, fields, }, i, )) - } else { - Err(LangError::UnexpectedToken) } } @@ -678,3 +695,44 @@ pub(super) fn parse_schema(c: &mut Compiler, m: RawSlice) -> LangResult { m }) } + +pub(super) fn parse_space_from_tokens(tok: &[Token], s: RawSlice) -> LangResult<(Space, usize)> { + let space_name = unsafe { s.as_str() }.into(); + + // let's see if the cursor is at `with`. ignore other tokens because that's fine + if !tok.is_empty() && tok[0] == Token::Keyword(Keyword::DdlMisc(DdlMiscKeyword::With)) { + // we have a dict + let mut d = Dict::new(); + let ret = self::rfold_dict(DictFoldState::OB, &tok[1..], &mut d); + if ret & HIBIT == HIBIT { + Ok(( + Space { + space_name, + props: d, + }, + (ret & !HIBIT) as _, + )) + } else { + Err(LangError::UnexpectedToken) + } + } else { + Ok(( + Space { + space_name, + props: dict! {}, + }, + 0, + )) + } +} + +pub(super) fn parse_space(c: &mut Compiler, s: RawSlice) -> LangResult { + self::parse_space_from_tokens(c.remslice(), s).map(|(m, i)| { + unsafe { + // UNSAFE(@ohsayan): The rfolds are very well tested to return the correct cursor position, + // so this should be completely safe + c.incr_cursor_by(i); + } + m + }) +}