|
|
|
@ -24,8 +24,14 @@
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
use std::mem::MaybeUninit;
|
|
|
|
|
|
|
|
|
|
use {
|
|
|
|
|
super::lexer::{Lit, Symbol, Token},
|
|
|
|
|
super::{
|
|
|
|
|
ast::Entity,
|
|
|
|
|
lexer::{Lit, Symbol, Token},
|
|
|
|
|
LangError, LangResult,
|
|
|
|
|
},
|
|
|
|
|
crate::engine::memory::DataType,
|
|
|
|
|
std::{
|
|
|
|
|
collections::HashMap,
|
|
|
|
@ -100,11 +106,10 @@ pub(super) fn parse_list_full(tok: &[Token]) -> Option<Vec<DataType>> {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
/// Parse the tuple data passed in with an insert query.
|
|
|
|
|
///
|
|
|
|
|
/// **Note:** Make sure you pass the `(` token
|
|
|
|
|
pub(super) fn parse_data_tuple_syntax(tok: &[Token]) -> (Vec<DataType>, usize, bool) {
|
|
|
|
|
pub(super) fn parse_data_tuple_syntax(tok: &[Token]) -> (Vec<Option<DataType>>, usize, bool) {
|
|
|
|
|
let l = tok.len();
|
|
|
|
|
let mut okay = l != 0;
|
|
|
|
|
let mut stop = okay && tok[0] == Token::Symbol(Symbol::TtCloseParen);
|
|
|
|
@ -113,22 +118,25 @@ pub(super) fn parse_data_tuple_syntax(tok: &[Token]) -> (Vec<DataType>, usize, b
|
|
|
|
|
while i < l && okay && !stop {
|
|
|
|
|
match &tok[i] {
|
|
|
|
|
Token::Lit(Lit::Str(s)) => {
|
|
|
|
|
data.push(s.to_string().into());
|
|
|
|
|
data.push(Some(s.to_string().into()));
|
|
|
|
|
}
|
|
|
|
|
Token::Lit(Lit::Num(n)) => {
|
|
|
|
|
data.push((*n).into());
|
|
|
|
|
data.push(Some((*n).into()));
|
|
|
|
|
}
|
|
|
|
|
Token::Lit(Lit::Bool(b)) => {
|
|
|
|
|
data.push((*b).into());
|
|
|
|
|
data.push(Some((*b).into()));
|
|
|
|
|
}
|
|
|
|
|
Token::Symbol(Symbol::TtOpenSqBracket) => {
|
|
|
|
|
// ah, a list
|
|
|
|
|
let mut l = Vec::new();
|
|
|
|
|
let (_, lst_i, lst_okay) = parse_list(&tok[i + 1..], &mut l);
|
|
|
|
|
data.push(l.into());
|
|
|
|
|
data.push(Some(l.into()));
|
|
|
|
|
i += lst_i;
|
|
|
|
|
okay &= lst_okay;
|
|
|
|
|
}
|
|
|
|
|
Token![null] => {
|
|
|
|
|
data.push(None);
|
|
|
|
|
}
|
|
|
|
|
_ => {
|
|
|
|
|
okay = false;
|
|
|
|
|
break;
|
|
|
|
@ -145,7 +153,7 @@ pub(super) fn parse_data_tuple_syntax(tok: &[Token]) -> (Vec<DataType>, usize, b
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
pub(super) fn parse_data_tuple_syntax_full(tok: &[Token]) -> Option<Vec<DataType>> {
|
|
|
|
|
pub(super) fn parse_data_tuple_syntax_full(tok: &[Token]) -> Option<Vec<Option<DataType>>> {
|
|
|
|
|
let (ret, cnt, okay) = parse_data_tuple_syntax(tok);
|
|
|
|
|
if cnt == tok.len() && okay {
|
|
|
|
|
Some(ret)
|
|
|
|
@ -154,7 +162,9 @@ pub(super) fn parse_data_tuple_syntax_full(tok: &[Token]) -> Option<Vec<DataType
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(super) fn parse_data_map_syntax(tok: &[Token]) -> (HashMap<Box<str>, DataType>, usize, bool) {
|
|
|
|
|
pub(super) fn parse_data_map_syntax<'a>(
|
|
|
|
|
tok: &'a [Token],
|
|
|
|
|
) -> (HashMap<&'a [u8], Option<DataType>>, usize, bool) {
|
|
|
|
|
let l = tok.len();
|
|
|
|
|
let mut okay = l != 0;
|
|
|
|
|
let mut stop = okay && tok[0] == Token::Symbol(Symbol::TtCloseBrace);
|
|
|
|
@ -166,17 +176,17 @@ pub(super) fn parse_data_map_syntax(tok: &[Token]) -> (HashMap<Box<str>, DataTyp
|
|
|
|
|
match (field, expression) {
|
|
|
|
|
(Token::Ident(id), Token::Lit(Lit::Str(s))) => {
|
|
|
|
|
okay &= data
|
|
|
|
|
.insert(unsafe { id.as_str() }.into(), s.to_string().into())
|
|
|
|
|
.insert(unsafe { id.as_slice() }, Some(s.to_string().into()))
|
|
|
|
|
.is_none();
|
|
|
|
|
}
|
|
|
|
|
(Token::Ident(id), Token::Lit(Lit::Num(n))) => {
|
|
|
|
|
okay &= data
|
|
|
|
|
.insert(unsafe { id.as_str() }.into(), (*n).into())
|
|
|
|
|
.insert(unsafe { id.as_slice() }, Some((*n).into()))
|
|
|
|
|
.is_none();
|
|
|
|
|
}
|
|
|
|
|
(Token::Ident(id), Token::Lit(Lit::Bool(b))) => {
|
|
|
|
|
okay &= data
|
|
|
|
|
.insert(unsafe { id.as_str() }.into(), (*b).into())
|
|
|
|
|
.insert(unsafe { id.as_slice() }, Some((*b).into()))
|
|
|
|
|
.is_none();
|
|
|
|
|
}
|
|
|
|
|
(Token::Ident(id), Token::Symbol(Symbol::TtOpenSqBracket)) => {
|
|
|
|
@ -186,9 +196,12 @@ pub(super) fn parse_data_map_syntax(tok: &[Token]) -> (HashMap<Box<str>, DataTyp
|
|
|
|
|
okay &= lst_ok;
|
|
|
|
|
i += lst_i;
|
|
|
|
|
okay &= data
|
|
|
|
|
.insert(unsafe { id.as_str() }.into(), l.into())
|
|
|
|
|
.insert(unsafe { id.as_slice() }, Some(l.into()))
|
|
|
|
|
.is_none();
|
|
|
|
|
}
|
|
|
|
|
(Token::Ident(id), Token![null]) => {
|
|
|
|
|
okay &= data.insert(unsafe { id.as_slice() }, None).is_none();
|
|
|
|
|
}
|
|
|
|
|
_ => {
|
|
|
|
|
okay = false;
|
|
|
|
|
break;
|
|
|
|
@ -196,19 +209,133 @@ pub(super) fn parse_data_map_syntax(tok: &[Token]) -> (HashMap<Box<str>, DataTyp
|
|
|
|
|
}
|
|
|
|
|
i += 3;
|
|
|
|
|
let nx_comma = i < l && tok[i] == Symbol::SymComma;
|
|
|
|
|
let nx_csprn = i < l && tok[i] == Symbol::TtCloseBrace;
|
|
|
|
|
okay &= nx_comma | nx_csprn;
|
|
|
|
|
let nx_csbrc = i < l && tok[i] == Symbol::TtCloseBrace;
|
|
|
|
|
okay &= nx_comma | nx_csbrc;
|
|
|
|
|
i += okay as usize;
|
|
|
|
|
stop = nx_csprn;
|
|
|
|
|
stop = nx_csbrc;
|
|
|
|
|
}
|
|
|
|
|
(data, i, okay && stop)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
pub(super) fn parse_data_map_syntax_full(tok: &[Token]) -> Option<HashMap<Box<str>, DataType>> {
|
|
|
|
|
pub(super) fn parse_data_map_syntax_full(
|
|
|
|
|
tok: &[Token],
|
|
|
|
|
) -> Option<HashMap<Box<str>, Option<DataType>>> {
|
|
|
|
|
let (dat, i, ok) = parse_data_map_syntax(tok);
|
|
|
|
|
if i == tok.len() && ok {
|
|
|
|
|
Some(dat)
|
|
|
|
|
Some(
|
|
|
|
|
dat.into_iter()
|
|
|
|
|
.map(|(ident, val)| {
|
|
|
|
|
(
|
|
|
|
|
String::from_utf8_lossy(ident).to_string().into_boxed_str(),
|
|
|
|
|
val,
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
.collect(),
|
|
|
|
|
)
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
|
pub enum InsertData<'a> {
|
|
|
|
|
Ordered(Vec<Option<DataType>>),
|
|
|
|
|
Map(HashMap<&'a [u8], Option<DataType>>),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> From<Vec<Option<DataType>>> for InsertData<'a> {
|
|
|
|
|
fn from(v: Vec<Option<DataType>>) -> Self {
|
|
|
|
|
Self::Ordered(v)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> From<HashMap<&'static [u8], Option<DataType>>> for InsertData<'a> {
|
|
|
|
|
fn from(m: HashMap<&'static [u8], Option<DataType>>) -> Self {
|
|
|
|
|
Self::Map(m)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
|
pub struct InsertStatement<'a> {
|
|
|
|
|
pub(super) primary_key: &'a Lit,
|
|
|
|
|
pub(super) entity: Entity,
|
|
|
|
|
pub(super) data: InsertData<'a>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(super) fn parse_insert<'a>(
|
|
|
|
|
src: &'a [Token],
|
|
|
|
|
counter: &mut usize,
|
|
|
|
|
) -> LangResult<InsertStatement<'a>> {
|
|
|
|
|
/*
|
|
|
|
|
smallest:
|
|
|
|
|
insert space:primary_key ()
|
|
|
|
|
^1 ^2 ^3^4 ^^5,6
|
|
|
|
|
*/
|
|
|
|
|
let l = src.len();
|
|
|
|
|
let is_full = Entity::tokens_with_full(src);
|
|
|
|
|
let is_half = Entity::tokens_with_single(src);
|
|
|
|
|
|
|
|
|
|
let mut okay = is_full | is_half;
|
|
|
|
|
let mut i = 0;
|
|
|
|
|
let mut entity = MaybeUninit::uninit();
|
|
|
|
|
|
|
|
|
|
if is_full {
|
|
|
|
|
i += 3;
|
|
|
|
|
entity = MaybeUninit::new(unsafe { Entity::full_entity_from_slice(src) });
|
|
|
|
|
} else if is_half {
|
|
|
|
|
i += 1;
|
|
|
|
|
entity = MaybeUninit::new(unsafe { Entity::single_entity_from_slice(src) });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// primary key is a lit; atleast lit + (<oparen><cparen>) | (<obrace><cbrace>)
|
|
|
|
|
okay &= l >= (i + 4);
|
|
|
|
|
// colon, lit
|
|
|
|
|
okay &= src[i] == Token![:] && src[i + 1].is_lit();
|
|
|
|
|
// check data
|
|
|
|
|
let is_map = okay && src[i + 2] == Token![open {}];
|
|
|
|
|
let is_tuple = okay && src[i + 2] == Token![() open];
|
|
|
|
|
okay &= is_map | is_tuple;
|
|
|
|
|
|
|
|
|
|
if !okay {
|
|
|
|
|
return Err(LangError::UnexpectedToken);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let primary_key = unsafe { extract!(&src[i+1], Token::Lit(l) => l) };
|
|
|
|
|
i += 3; // skip col, lit + op/ob
|
|
|
|
|
|
|
|
|
|
let data;
|
|
|
|
|
if is_tuple {
|
|
|
|
|
let (ord, cnt, ok) = parse_data_tuple_syntax(&src[i..]);
|
|
|
|
|
okay &= ok;
|
|
|
|
|
i += cnt;
|
|
|
|
|
data = InsertData::Ordered(ord);
|
|
|
|
|
} else {
|
|
|
|
|
let (map, cnt, ok) = parse_data_map_syntax(&src[i..]);
|
|
|
|
|
okay &= ok;
|
|
|
|
|
i += cnt;
|
|
|
|
|
data = InsertData::Map(map);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*counter += i;
|
|
|
|
|
|
|
|
|
|
if okay {
|
|
|
|
|
Ok(InsertStatement {
|
|
|
|
|
primary_key,
|
|
|
|
|
entity: unsafe { entity.assume_init() },
|
|
|
|
|
data,
|
|
|
|
|
})
|
|
|
|
|
} else {
|
|
|
|
|
Err(LangError::UnexpectedToken)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
pub(super) fn parse_insert_full<'a>(tok: &'a [Token]) -> Option<InsertStatement<'a>> {
|
|
|
|
|
let mut z = 0;
|
|
|
|
|
let s = self::parse_insert(tok, &mut z);
|
|
|
|
|
if z == tok.len() {
|
|
|
|
|
s.ok()
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|