Refactor functions to use standard function vocab parser
This commit is contained in:
parent
5fab151451
commit
e937a7221f
13 changed files with 236 additions and 145 deletions
|
@ -150,14 +150,12 @@ fn box_error_with_ctx<E: MpsLanguageError + 'static>(
|
||||||
|
|
||||||
pub(crate) fn standard_vocab(vocabulary: &mut MpsLanguageDictionary) {
|
pub(crate) fn standard_vocab(vocabulary: &mut MpsLanguageDictionary) {
|
||||||
vocabulary
|
vocabulary
|
||||||
// high-priority vocabulary (low-priority may accept this, but will not execute as expected)
|
|
||||||
.add(crate::lang::vocabulary::filters::empty_filter())
|
.add(crate::lang::vocabulary::filters::empty_filter())
|
||||||
.add(crate::lang::vocabulary::filters::field_filter())
|
.add(crate::lang::vocabulary::filters::field_filter())
|
||||||
// low-priority (more forgiving statements which may not parse complete statement)
|
.add(crate::lang::vocabulary::sql_function_factory())
|
||||||
.add(crate::lang::vocabulary::SqlStatementFactory)
|
.add(crate::lang::vocabulary::simple_sql_function_factory())
|
||||||
.add(crate::lang::vocabulary::SimpleSqlStatementFactory)
|
|
||||||
.add(crate::lang::vocabulary::CommentStatementFactory)
|
.add(crate::lang::vocabulary::CommentStatementFactory)
|
||||||
.add(crate::lang::vocabulary::RepeatStatementFactory)
|
.add(crate::lang::vocabulary::repeat_function_factory())
|
||||||
.add(crate::lang::vocabulary::AssignStatementFactory)
|
.add(crate::lang::vocabulary::AssignStatementFactory)
|
||||||
.add(crate::lang::vocabulary::SqlInitStatementFactory);
|
.add(crate::lang::vocabulary::sql_init_function_factory());
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,9 +25,18 @@ impl MpsLanguageDictionary {
|
||||||
return factory.build_op_boxed(tokens, self);
|
return factory.build_op_boxed(tokens, self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let result = match tokens.pop_front() {
|
||||||
|
Some(x) => Ok(x),
|
||||||
|
None => Err(SyntaxError {
|
||||||
|
line: 0,
|
||||||
|
token: MpsToken::Name("???".into()),
|
||||||
|
got: None,
|
||||||
|
})
|
||||||
|
}?;
|
||||||
Err(SyntaxError {
|
Err(SyntaxError {
|
||||||
line: 0,
|
line: 0,
|
||||||
token: tokens.pop_front().unwrap(),
|
token: MpsToken::Name("???".into()),
|
||||||
|
got: Some(result),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,15 +7,23 @@ use crate::tokens::MpsToken;
|
||||||
pub struct SyntaxError {
|
pub struct SyntaxError {
|
||||||
pub line: usize,
|
pub line: usize,
|
||||||
pub token: MpsToken,
|
pub token: MpsToken,
|
||||||
|
pub got: Option<MpsToken>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for SyntaxError {
|
impl Display for SyntaxError {
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||||
write!(
|
match &self.got {
|
||||||
|
Some(t) => write!(
|
||||||
f,
|
f,
|
||||||
"SyntaxError (line {}): Unexpected {}",
|
"SyntaxError (line {}): Expected {}, got {}",
|
||||||
|
&self.line, &self.token, t
|
||||||
|
),
|
||||||
|
None => write!(
|
||||||
|
f,
|
||||||
|
"SyntaxError (line {}): Expected {}, got nothing",
|
||||||
&self.line, &self.token
|
&self.line, &self.token
|
||||||
)
|
),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
68
mps-interpreter/src/lang/function.rs
Normal file
68
mps-interpreter/src/lang/function.rs
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
//use std::fmt::{Debug, Display, Error, Formatter};
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use crate::tokens::MpsToken;
|
||||||
|
use crate::lang::{MpsOp, BoxedMpsOpFactory};
|
||||||
|
use crate::lang::SyntaxError;
|
||||||
|
use crate::lang::MpsLanguageDictionary;
|
||||||
|
use crate::lang::utility::{assert_token_raw, assert_token_raw_back, assert_token};
|
||||||
|
|
||||||
|
pub trait MpsFunctionFactory<Op: MpsOp + 'static> {
|
||||||
|
fn is_function(&self, name: &str) -> bool;
|
||||||
|
|
||||||
|
fn build_function_params(
|
||||||
|
&self,
|
||||||
|
name: String,
|
||||||
|
tokens: &mut VecDeque<MpsToken>,
|
||||||
|
dict: &MpsLanguageDictionary,
|
||||||
|
) -> Result<Op, SyntaxError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MpsFunctionStatementFactory<Op: MpsOp + 'static, F: MpsFunctionFactory<Op> + 'static> {
|
||||||
|
op_factory: F,
|
||||||
|
idc: PhantomData<Op>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Op: MpsOp + 'static, F: MpsFunctionFactory<Op> + 'static> MpsFunctionStatementFactory<Op, F> {
|
||||||
|
pub fn new(factory: F) -> Self {
|
||||||
|
Self {
|
||||||
|
op_factory: factory,
|
||||||
|
idc: PhantomData::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Op: MpsOp + 'static, F: MpsFunctionFactory<Op> + 'static>
|
||||||
|
BoxedMpsOpFactory
|
||||||
|
for
|
||||||
|
MpsFunctionStatementFactory<Op, F>
|
||||||
|
{
|
||||||
|
fn is_op_boxed(&self, tokens: &VecDeque<MpsToken>) -> bool {
|
||||||
|
let tokens_len = tokens.len();
|
||||||
|
if tokens_len < 3 {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
match &tokens[0] {
|
||||||
|
MpsToken::Name(n) => self.op_factory.is_function(n)
|
||||||
|
&& tokens[1].is_open_bracket()
|
||||||
|
&& tokens[tokens_len - 1].is_close_bracket(),
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_op_boxed(
|
||||||
|
&self,
|
||||||
|
tokens: &mut VecDeque<MpsToken>,
|
||||||
|
dict: &MpsLanguageDictionary,
|
||||||
|
) -> Result<Box<dyn MpsOp>, SyntaxError> {
|
||||||
|
let name = assert_token(|t| match t {
|
||||||
|
MpsToken::Name(n) => Some(n),
|
||||||
|
_ => None
|
||||||
|
}, MpsToken::Name("function_name".into()), tokens)?;
|
||||||
|
assert_token_raw(MpsToken::OpenBracket, tokens)?;
|
||||||
|
assert_token_raw_back(MpsToken::CloseBracket, tokens)?;
|
||||||
|
Ok(Box::new(self.op_factory.build_function_params(name, tokens, dict)?))
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ mod db_items;
|
||||||
mod dictionary;
|
mod dictionary;
|
||||||
mod error;
|
mod error;
|
||||||
mod filter;
|
mod filter;
|
||||||
|
mod function;
|
||||||
mod operation;
|
mod operation;
|
||||||
mod pseudo_op;
|
mod pseudo_op;
|
||||||
mod repeated_meme;
|
mod repeated_meme;
|
||||||
|
@ -12,6 +13,7 @@ pub(crate) mod utility;
|
||||||
pub use dictionary::MpsLanguageDictionary;
|
pub use dictionary::MpsLanguageDictionary;
|
||||||
pub use error::{MpsLanguageError, RuntimeError, SyntaxError};
|
pub use error::{MpsLanguageError, RuntimeError, SyntaxError};
|
||||||
pub use filter::{MpsFilterFactory, MpsFilterPredicate, MpsFilterStatement, MpsFilterStatementFactory};
|
pub use filter::{MpsFilterFactory, MpsFilterPredicate, MpsFilterStatement, MpsFilterStatementFactory};
|
||||||
|
pub use function::{MpsFunctionFactory, MpsFunctionStatementFactory};
|
||||||
pub use operation::{BoxedMpsOpFactory, MpsOp, MpsOpFactory, SimpleMpsOpFactory};
|
pub use operation::{BoxedMpsOpFactory, MpsOp, MpsOpFactory, SimpleMpsOpFactory};
|
||||||
pub use pseudo_op::PseudoOp;
|
pub use pseudo_op::PseudoOp;
|
||||||
pub use repeated_meme::{RepeatedTokens, repeated_tokens};
|
pub use repeated_meme::{RepeatedTokens, repeated_tokens};
|
||||||
|
|
|
@ -11,12 +11,21 @@ pub fn assert_token<T, F: FnOnce(MpsToken) -> Option<T>>(
|
||||||
token: MpsToken,
|
token: MpsToken,
|
||||||
tokens: &mut VecDeque<MpsToken>,
|
tokens: &mut VecDeque<MpsToken>,
|
||||||
) -> Result<T, SyntaxError> {
|
) -> Result<T, SyntaxError> {
|
||||||
if let Some(out) = caster(tokens.pop_front().unwrap()) {
|
let result = match tokens.pop_front() {
|
||||||
|
Some(x) => Ok(x),
|
||||||
|
None => Err(SyntaxError {
|
||||||
|
line: 0,
|
||||||
|
token: token.clone(),
|
||||||
|
got: None,
|
||||||
|
})
|
||||||
|
}?;
|
||||||
|
if let Some(out) = caster(result.clone()) {
|
||||||
Ok(out)
|
Ok(out)
|
||||||
} else {
|
} else {
|
||||||
Err(SyntaxError {
|
Err(SyntaxError {
|
||||||
line: 0,
|
line: 0,
|
||||||
token: token,
|
token: token,
|
||||||
|
got: Some(result),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,13 +34,44 @@ pub fn assert_token_raw(
|
||||||
token: MpsToken,
|
token: MpsToken,
|
||||||
tokens: &mut VecDeque<MpsToken>,
|
tokens: &mut VecDeque<MpsToken>,
|
||||||
) -> Result<MpsToken, SyntaxError> {
|
) -> Result<MpsToken, SyntaxError> {
|
||||||
let result = tokens.pop_front().unwrap();
|
let result = match tokens.pop_front() {
|
||||||
|
Some(x) => Ok(x),
|
||||||
|
None => Err(SyntaxError {
|
||||||
|
line: 0,
|
||||||
|
token: token.clone(),
|
||||||
|
got: None,
|
||||||
|
})
|
||||||
|
}?;
|
||||||
if std::mem::discriminant(&token) == std::mem::discriminant(&result) {
|
if std::mem::discriminant(&token) == std::mem::discriminant(&result) {
|
||||||
Ok(result)
|
Ok(result)
|
||||||
} else {
|
} else {
|
||||||
Err(SyntaxError {
|
Err(SyntaxError {
|
||||||
line: 0,
|
line: 0,
|
||||||
token: token,
|
token: token,
|
||||||
|
got: Some(result),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn assert_token_raw_back(
|
||||||
|
token: MpsToken,
|
||||||
|
tokens: &mut VecDeque<MpsToken>,
|
||||||
|
) -> Result<MpsToken, SyntaxError> {
|
||||||
|
let result = match tokens.pop_back() {
|
||||||
|
Some(x) => Ok(x),
|
||||||
|
None => Err(SyntaxError {
|
||||||
|
line: 0,
|
||||||
|
token: token.clone(),
|
||||||
|
got: None,
|
||||||
|
})
|
||||||
|
}?;
|
||||||
|
if std::mem::discriminant(&token) == std::mem::discriminant(&result) {
|
||||||
|
Ok(result)
|
||||||
|
} else {
|
||||||
|
Err(SyntaxError {
|
||||||
|
line: 0,
|
||||||
|
token: token,
|
||||||
|
got: Some(result),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,8 +83,17 @@ pub fn check_token_raw(
|
||||||
std::mem::discriminant(&token) == std::mem::discriminant(token_target)
|
std::mem::discriminant(&token) == std::mem::discriminant(token_target)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn assert_name(name: &str, tokens: &mut VecDeque<MpsToken>) -> Result<String, SyntaxError> {
|
pub fn assert_name(name: &str, tokens: &mut VecDeque<MpsToken>) -> Result<String, SyntaxError> {
|
||||||
match tokens.pop_front().unwrap() {
|
let result = match tokens.pop_front() {
|
||||||
|
Some(x) => Ok(x),
|
||||||
|
None => Err(SyntaxError {
|
||||||
|
line: 0,
|
||||||
|
token: MpsToken::Name(name.to_owned()),
|
||||||
|
got: None,
|
||||||
|
})
|
||||||
|
}?;
|
||||||
|
match result {
|
||||||
MpsToken::Name(n) => {
|
MpsToken::Name(n) => {
|
||||||
if n == name {
|
if n == name {
|
||||||
Ok(n)
|
Ok(n)
|
||||||
|
@ -53,17 +102,20 @@ pub fn assert_name(name: &str, tokens: &mut VecDeque<MpsToken>) -> Result<String
|
||||||
SyntaxError {
|
SyntaxError {
|
||||||
line: 0,
|
line: 0,
|
||||||
token: MpsToken::Name(name.to_owned()),
|
token: MpsToken::Name(name.to_owned()),
|
||||||
|
got: Some(MpsToken::Name(n)),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_token => Err(SyntaxError {
|
token => Err(SyntaxError {
|
||||||
line: 0,
|
line: 0,
|
||||||
token: MpsToken::Name(name.to_owned()),
|
token: MpsToken::Name(name.to_owned()),
|
||||||
|
got: Some(token),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn check_name(name: &str, token: &MpsToken) -> bool {
|
pub fn check_name(name: &str, token: &MpsToken) -> bool {
|
||||||
match token {
|
match token {
|
||||||
MpsToken::Name(n) => n == name,
|
MpsToken::Name(n) => n == name,
|
||||||
|
@ -85,7 +137,15 @@ pub fn check_is_type(token: &MpsToken) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assert_type(tokens: &mut VecDeque<MpsToken>) -> Result<MpsTypePrimitive, SyntaxError> {
|
pub fn assert_type(tokens: &mut VecDeque<MpsToken>) -> Result<MpsTypePrimitive, SyntaxError> {
|
||||||
match tokens.pop_front().unwrap() {
|
let token = match tokens.pop_front() {
|
||||||
|
Some(x) => Ok(x),
|
||||||
|
None => Err(SyntaxError {
|
||||||
|
line: 0,
|
||||||
|
token: MpsToken::Name("Float | UInt | Int | Bool".into()),
|
||||||
|
got: None,
|
||||||
|
})
|
||||||
|
}?;
|
||||||
|
match token {
|
||||||
MpsToken::Literal(s) => Ok(MpsTypePrimitive::String(s)),
|
MpsToken::Literal(s) => Ok(MpsTypePrimitive::String(s)),
|
||||||
MpsToken::Name(s) => {
|
MpsToken::Name(s) => {
|
||||||
if let Ok(f) = s.parse::<f64>() {
|
if let Ok(f) = s.parse::<f64>() {
|
||||||
|
@ -102,12 +162,14 @@ pub fn assert_type(tokens: &mut VecDeque<MpsToken>) -> Result<MpsTypePrimitive,
|
||||||
Err(SyntaxError {
|
Err(SyntaxError {
|
||||||
line: 0,
|
line: 0,
|
||||||
token: MpsToken::Name("Float | UInt | Int | Bool".into()),
|
token: MpsToken::Name("Float | UInt | Int | Bool".into()),
|
||||||
|
got: Some(MpsToken::Name(s))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_token => Err(SyntaxError {
|
token => Err(SyntaxError {
|
||||||
line: 0,
|
line: 0,
|
||||||
token: MpsToken::Name("Float | UInt | Int | Bool | \"String\"".into()),
|
token: MpsToken::Name("Float | UInt | Int | Bool | \"String\"".into()),
|
||||||
|
got: Some(token)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ pub fn assert_comparison_operator(tokens: &mut VecDeque<MpsToken>) -> Result<[i8
|
||||||
Err(SyntaxError {
|
Err(SyntaxError {
|
||||||
line: 0,
|
line: 0,
|
||||||
token: MpsToken::Equals,
|
token: MpsToken::Equals,
|
||||||
|
got: if tokens.len() != 0 {Some(tokens[0].clone())} else {None},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -52,6 +53,7 @@ pub fn assert_comparison_operator(tokens: &mut VecDeque<MpsToken>) -> Result<[i8
|
||||||
_ => Err(SyntaxError {
|
_ => Err(SyntaxError {
|
||||||
line: 0,
|
line: 0,
|
||||||
token: MpsToken::Equals, // TODO this can be < > or =
|
token: MpsToken::Equals, // TODO this can be < > or =
|
||||||
|
got: Some(token1),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,10 @@ mod sql_query;
|
||||||
mod sql_simple_query;
|
mod sql_simple_query;
|
||||||
mod variable_assign;
|
mod variable_assign;
|
||||||
|
|
||||||
pub use sql_query::{SqlStatement, SqlStatementFactory};
|
pub use sql_query::{SqlStatementFactory, sql_function_factory};
|
||||||
pub use sql_simple_query::{SimpleSqlStatement, SimpleSqlStatementFactory};
|
pub use sql_simple_query::{SimpleSqlStatementFactory, simple_sql_function_factory};
|
||||||
pub use comment::{CommentStatement, CommentStatementFactory};
|
pub use comment::{CommentStatement, CommentStatementFactory};
|
||||||
pub use repeat::{RepeatStatement, RepeatStatementFactory};
|
pub use repeat::{RepeatStatementFactory, repeat_function_factory};
|
||||||
pub use variable_assign::{AssignStatement, AssignStatementFactory};
|
pub use variable_assign::{AssignStatement, AssignStatementFactory};
|
||||||
pub use sql_init::{SqlInitStatement, SqlInitStatementFactory};
|
pub use sql_init::{SqlInitStatementFactory, sql_init_function_factory};
|
||||||
pub mod filters;
|
pub mod filters;
|
||||||
|
|
|
@ -7,9 +7,9 @@ use crate::MpsMusicItem;
|
||||||
use crate::tokens::MpsToken;
|
use crate::tokens::MpsToken;
|
||||||
|
|
||||||
use crate::lang::{RuntimeError, SyntaxError};
|
use crate::lang::{RuntimeError, SyntaxError};
|
||||||
use crate::lang::{MpsOp, PseudoOp, MpsOpFactory, BoxedMpsOpFactory};
|
use crate::lang::{MpsOp, PseudoOp, MpsFunctionFactory, MpsFunctionStatementFactory};
|
||||||
use crate::lang::MpsLanguageDictionary;
|
use crate::lang::MpsLanguageDictionary;
|
||||||
use crate::lang::utility::{assert_name, assert_token_raw, assert_token, check_name};
|
use crate::lang::utility::{assert_token_raw, assert_token};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct RepeatStatement {
|
pub struct RepeatStatement {
|
||||||
|
@ -113,34 +113,30 @@ impl MpsOp for RepeatStatement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RepeatStatementFactory;
|
pub struct RepeatFunctionFactory;
|
||||||
|
|
||||||
impl MpsOpFactory<RepeatStatement> for RepeatStatementFactory {
|
impl MpsFunctionFactory<RepeatStatement> for RepeatFunctionFactory {
|
||||||
fn is_op(&self, tokens: &VecDeque<MpsToken>) -> bool {
|
fn is_function(&self, name: &str) -> bool {
|
||||||
tokens.len() >= 3
|
name == "repeat"
|
||||||
&& check_name("repeat", &tokens[0])
|
|
||||||
&& tokens[1].is_open_bracket()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_op(
|
fn build_function_params(
|
||||||
&self,
|
&self,
|
||||||
|
_name: String,
|
||||||
tokens: &mut VecDeque<MpsToken>,
|
tokens: &mut VecDeque<MpsToken>,
|
||||||
dict: &MpsLanguageDictionary,
|
dict: &MpsLanguageDictionary,
|
||||||
) -> Result<RepeatStatement, SyntaxError> {
|
) -> Result<RepeatStatement, SyntaxError> {
|
||||||
// repeat(query) or repeat(query, repetitions)
|
// repeat(query) or repeat(query, repetitions)
|
||||||
assert_name("repeat", tokens)?;
|
let end_tokens = tokens.split_off(next_comma(tokens));
|
||||||
assert_token_raw(MpsToken::OpenBracket, tokens)?;
|
|
||||||
let inner_statement = dict.try_build_statement(tokens)?;
|
let inner_statement = dict.try_build_statement(tokens)?;
|
||||||
|
tokens.extend(end_tokens);
|
||||||
let mut count: Option<usize> = None;
|
let mut count: Option<usize> = None;
|
||||||
if tokens[0].is_close_bracket() { // no repititions
|
if tokens.len() != 0 { // repititions specified
|
||||||
assert_token_raw(MpsToken::CloseBracket, tokens)?;
|
|
||||||
} else if tokens[0].is_comma() { // repetitions specified
|
|
||||||
assert_token_raw(MpsToken::Comma, tokens)?;
|
assert_token_raw(MpsToken::Comma, tokens)?;
|
||||||
count = Some(assert_token(|t| match t {
|
count = Some(assert_token(|t| match t {
|
||||||
MpsToken::Name(n) => n.parse::<usize>().map(|d| d - 1).ok(),
|
MpsToken::Name(n) => n.parse::<usize>().map(|d| d - 1).ok(),
|
||||||
_ => None
|
_ => None
|
||||||
}, MpsToken::Name("usize".into()), tokens)?);
|
}, MpsToken::Name("usize".into()), tokens)?);
|
||||||
assert_token_raw(MpsToken::CloseBracket, tokens)?;
|
|
||||||
}
|
}
|
||||||
Ok(RepeatStatement {
|
Ok(RepeatStatement {
|
||||||
inner_statement: inner_statement.into(),
|
inner_statement: inner_statement.into(),
|
||||||
|
@ -154,16 +150,18 @@ impl MpsOpFactory<RepeatStatement> for RepeatStatementFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BoxedMpsOpFactory for RepeatStatementFactory {
|
fn next_comma(tokens: &VecDeque<MpsToken>) -> usize {
|
||||||
fn build_op_boxed(
|
for i in 0..tokens.len() {
|
||||||
&self,
|
if tokens[i].is_comma() {
|
||||||
tokens: &mut VecDeque<MpsToken>,
|
return i;
|
||||||
dict: &MpsLanguageDictionary,
|
|
||||||
) -> Result<Box<dyn MpsOp>, SyntaxError> {
|
|
||||||
self.build_box(tokens, dict)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_op_boxed(&self, tokens: &VecDeque<MpsToken>) -> bool {
|
|
||||||
self.is_op(tokens)
|
|
||||||
}
|
}
|
||||||
|
tokens.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type RepeatStatementFactory = MpsFunctionStatementFactory<RepeatStatement, RepeatFunctionFactory>;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn repeat_function_factory() -> RepeatStatementFactory {
|
||||||
|
RepeatStatementFactory::new(RepeatFunctionFactory)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,9 @@ use crate::MpsMusicItem;
|
||||||
use crate::tokens::MpsToken;
|
use crate::tokens::MpsToken;
|
||||||
|
|
||||||
use crate::lang::{RuntimeError, SyntaxError};
|
use crate::lang::{RuntimeError, SyntaxError};
|
||||||
use crate::lang::{MpsOp, SimpleMpsOpFactory, MpsOpFactory, BoxedMpsOpFactory};
|
use crate::lang::{MpsOp, MpsFunctionFactory, MpsFunctionStatementFactory};
|
||||||
use crate::lang::MpsLanguageDictionary;
|
use crate::lang::MpsLanguageDictionary;
|
||||||
use crate::lang::utility::{assert_token_raw, check_name, assert_name, assert_token};
|
use crate::lang::utility::{assert_token_raw, assert_token};
|
||||||
use crate::lang::repeated_tokens;
|
use crate::lang::repeated_tokens;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -62,21 +62,19 @@ impl MpsOp for SqlInitStatement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SqlInitStatementFactory;
|
pub struct SqlInitFunctionFactory;
|
||||||
|
|
||||||
impl SimpleMpsOpFactory<SqlInitStatement> for SqlInitStatementFactory {
|
impl MpsFunctionFactory<SqlInitStatement> for SqlInitFunctionFactory {
|
||||||
fn is_op_simple(&self, tokens: &VecDeque<MpsToken>) -> bool {
|
fn is_function(&self, name: &str) -> bool {
|
||||||
tokens.len() >= 3
|
name == "sql_init"
|
||||||
&& check_name("sql_init", &tokens[0])
|
|
||||||
&& tokens[1].is_open_bracket()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_op_simple(
|
fn build_function_params(
|
||||||
&self,
|
&self,
|
||||||
|
_name: String,
|
||||||
tokens: &mut VecDeque<MpsToken>,
|
tokens: &mut VecDeque<MpsToken>,
|
||||||
|
_dict: &MpsLanguageDictionary,
|
||||||
) -> Result<SqlInitStatement, SyntaxError> {
|
) -> Result<SqlInitStatement, SyntaxError> {
|
||||||
assert_name("sql_init", tokens)?;
|
|
||||||
assert_token_raw(MpsToken::OpenBracket, tokens)?;
|
|
||||||
let ingest = |tokens2: &mut VecDeque<MpsToken>| {
|
let ingest = |tokens2: &mut VecDeque<MpsToken>| {
|
||||||
if tokens2.len() < 3 {return Ok(None);} // nothing wrong, nothing left to ingest
|
if tokens2.len() < 3 {return Ok(None);} // nothing wrong, nothing left to ingest
|
||||||
let param_name = assert_token(|t| match t {
|
let param_name = assert_token(|t| match t {
|
||||||
|
@ -92,7 +90,6 @@ impl SimpleMpsOpFactory<SqlInitStatement> for SqlInitStatementFactory {
|
||||||
Ok(Some((param_name, param_val))) // successfully ingested one phrase
|
Ok(Some((param_name, param_val))) // successfully ingested one phrase
|
||||||
};
|
};
|
||||||
let params = repeated_tokens(ingest, MpsToken::Comma).ingest_all(tokens)?;
|
let params = repeated_tokens(ingest, MpsToken::Comma).ingest_all(tokens)?;
|
||||||
assert_token_raw(MpsToken::CloseBracket, tokens)?;
|
|
||||||
Ok(SqlInitStatement {
|
Ok(SqlInitStatement {
|
||||||
context: None,
|
context: None,
|
||||||
params: HashMap::from_iter(params),
|
params: HashMap::from_iter(params),
|
||||||
|
@ -100,16 +97,9 @@ impl SimpleMpsOpFactory<SqlInitStatement> for SqlInitStatementFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BoxedMpsOpFactory for SqlInitStatementFactory {
|
pub type SqlInitStatementFactory = MpsFunctionStatementFactory<SqlInitStatement, SqlInitFunctionFactory>;
|
||||||
fn build_op_boxed(
|
|
||||||
&self,
|
|
||||||
tokens: &mut VecDeque<MpsToken>,
|
|
||||||
dict: &MpsLanguageDictionary,
|
|
||||||
) -> Result<Box<dyn MpsOp>, SyntaxError> {
|
|
||||||
self.build_box(tokens, dict)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_op_boxed(&self, tokens: &VecDeque<MpsToken>) -> bool {
|
#[inline(always)]
|
||||||
self.is_op(tokens)
|
pub fn sql_init_function_factory() -> SqlInitStatementFactory {
|
||||||
}
|
SqlInitStatementFactory::new(SqlInitFunctionFactory)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@ use std::collections::VecDeque;
|
||||||
use std::fmt::{Debug, Display, Error, Formatter};
|
use std::fmt::{Debug, Display, Error, Formatter};
|
||||||
use std::iter::Iterator;
|
use std::iter::Iterator;
|
||||||
|
|
||||||
use crate::lang::utility::{assert_token, assert_token_raw, check_name, assert_name};
|
use crate::lang::utility::assert_token;
|
||||||
use crate::lang::{BoxedMpsOpFactory, MpsLanguageDictionary, MpsOp, MpsOpFactory};
|
use crate::lang::{MpsLanguageDictionary, MpsOp, MpsFunctionFactory, MpsFunctionStatementFactory};
|
||||||
use crate::lang::{RuntimeError, SyntaxError};
|
use crate::lang::{RuntimeError, SyntaxError};
|
||||||
use crate::tokens::MpsToken;
|
use crate::tokens::MpsToken;
|
||||||
use crate::MpsContext;
|
use crate::MpsContext;
|
||||||
|
@ -102,28 +102,20 @@ impl Display for SqlStatement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SqlStatementFactory;
|
pub struct SqlFunctionFactory;
|
||||||
|
|
||||||
impl MpsOpFactory<SqlStatement> for SqlStatementFactory {
|
impl MpsFunctionFactory<SqlStatement> for SqlFunctionFactory {
|
||||||
#[inline]
|
fn is_function(&self, name: &str) -> bool {
|
||||||
fn is_op(&self, tokens: &VecDeque<MpsToken>) -> bool {
|
name == "sql"
|
||||||
tokens.len() > 3
|
|
||||||
&& check_name("sql", &tokens[0])
|
|
||||||
&& tokens[1].is_open_bracket()
|
|
||||||
&& tokens[2].is_literal()
|
|
||||||
&& tokens[3].is_close_bracket()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
fn build_function_params(
|
||||||
fn build_op(
|
|
||||||
&self,
|
&self,
|
||||||
|
_name: String,
|
||||||
tokens: &mut VecDeque<MpsToken>,
|
tokens: &mut VecDeque<MpsToken>,
|
||||||
_dict: &MpsLanguageDictionary,
|
_dict: &MpsLanguageDictionary,
|
||||||
) -> Result<SqlStatement, SyntaxError> {
|
) -> Result<SqlStatement, SyntaxError> {
|
||||||
// sql ( `some query` )
|
// sql ( `some query` )
|
||||||
assert_name("sql", tokens)?;
|
|
||||||
//assert_token_raw(MpsToken::Sql, tokens)?;
|
|
||||||
assert_token_raw(MpsToken::OpenBracket, tokens)?;
|
|
||||||
let literal = assert_token(
|
let literal = assert_token(
|
||||||
|t| match t {
|
|t| match t {
|
||||||
MpsToken::Literal(query) => Some(query),
|
MpsToken::Literal(query) => Some(query),
|
||||||
|
@ -132,7 +124,6 @@ impl MpsOpFactory<SqlStatement> for SqlStatementFactory {
|
||||||
MpsToken::Literal("".into()),
|
MpsToken::Literal("".into()),
|
||||||
tokens,
|
tokens,
|
||||||
)?;
|
)?;
|
||||||
assert_token_raw(MpsToken::CloseBracket, tokens)?;
|
|
||||||
Ok(SqlStatement {
|
Ok(SqlStatement {
|
||||||
query: literal,
|
query: literal,
|
||||||
context: None,
|
context: None,
|
||||||
|
@ -142,16 +133,9 @@ impl MpsOpFactory<SqlStatement> for SqlStatementFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BoxedMpsOpFactory for SqlStatementFactory {
|
pub type SqlStatementFactory = MpsFunctionStatementFactory<SqlStatement, SqlFunctionFactory>;
|
||||||
fn build_op_boxed(
|
|
||||||
&self,
|
|
||||||
tokens: &mut VecDeque<MpsToken>,
|
|
||||||
dict: &MpsLanguageDictionary,
|
|
||||||
) -> Result<Box<dyn MpsOp>, SyntaxError> {
|
|
||||||
self.build_box(tokens, dict)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_op_boxed(&self, tokens: &VecDeque<MpsToken>) -> bool {
|
#[inline(always)]
|
||||||
self.is_op(tokens)
|
pub fn sql_function_factory() -> SqlStatementFactory {
|
||||||
}
|
SqlStatementFactory::new(SqlFunctionFactory)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@ use std::collections::VecDeque;
|
||||||
use std::fmt::{Debug, Display, Error, Formatter};
|
use std::fmt::{Debug, Display, Error, Formatter};
|
||||||
use std::iter::Iterator;
|
use std::iter::Iterator;
|
||||||
|
|
||||||
use crate::lang::utility::{assert_token, assert_token_raw};
|
use crate::lang::utility::assert_token;
|
||||||
use crate::lang::{BoxedMpsOpFactory, MpsLanguageDictionary, MpsOp, MpsOpFactory};
|
use crate::lang::{MpsLanguageDictionary, MpsOp, MpsFunctionFactory, MpsFunctionStatementFactory};
|
||||||
use crate::lang::{RuntimeError, SyntaxError};
|
use crate::lang::{RuntimeError, SyntaxError};
|
||||||
use crate::tokens::MpsToken;
|
use crate::tokens::MpsToken;
|
||||||
use crate::MpsContext;
|
use crate::MpsContext;
|
||||||
|
@ -26,7 +26,8 @@ impl QueryMode {
|
||||||
"genre" => Ok(QueryMode::Genre),
|
"genre" => Ok(QueryMode::Genre),
|
||||||
_ => Err(SyntaxError {
|
_ => Err(SyntaxError {
|
||||||
line: 0,
|
line: 0,
|
||||||
token: Self::tokenify(name),
|
token: MpsToken::Name("artist|album|song|genre".into()),
|
||||||
|
got: Some(Self::tokenify(name)),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,43 +163,20 @@ impl Display for SimpleSqlStatement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SimpleSqlStatementFactory;
|
pub struct SimpleSqlFunctionFactory;
|
||||||
|
|
||||||
impl MpsOpFactory<SimpleSqlStatement> for SimpleSqlStatementFactory {
|
impl MpsFunctionFactory<SimpleSqlStatement> for SimpleSqlFunctionFactory {
|
||||||
#[inline]
|
fn is_function(&self, name: &str) -> bool {
|
||||||
fn is_op(&self, tokens: &VecDeque<MpsToken>) -> bool {
|
QueryMode::is_valid_name(name)
|
||||||
tokens.len() > 3
|
|
||||||
&& match &tokens[0] {
|
|
||||||
MpsToken::Name(name) => QueryMode::is_valid_name(name),
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
&& tokens[1].is_open_bracket()
|
|
||||||
&& tokens[2].is_literal()
|
|
||||||
&& tokens[3].is_close_bracket()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
fn build_function_params(
|
||||||
fn build_op(
|
|
||||||
&self,
|
&self,
|
||||||
|
mode_name: String,
|
||||||
tokens: &mut VecDeque<MpsToken>,
|
tokens: &mut VecDeque<MpsToken>,
|
||||||
_dict: &MpsLanguageDictionary,
|
_dict: &MpsLanguageDictionary,
|
||||||
) -> Result<SimpleSqlStatement, SyntaxError> {
|
) -> Result<SimpleSqlStatement, SyntaxError> {
|
||||||
// artist|album|song|genre ( `like` )
|
// artist|album|song|genre ( `title_like` )
|
||||||
let mode_name = assert_token(
|
|
||||||
|t| match t {
|
|
||||||
MpsToken::Name(name) => {
|
|
||||||
if QueryMode::is_valid_name(&name) {
|
|
||||||
Some(name)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
MpsToken::Name("artist|album|song|genre".into()),
|
|
||||||
tokens,
|
|
||||||
)?;
|
|
||||||
assert_token_raw(MpsToken::OpenBracket, tokens)?;
|
|
||||||
let literal = assert_token(
|
let literal = assert_token(
|
||||||
|t| match t {
|
|t| match t {
|
||||||
MpsToken::Literal(query) => Some(query),
|
MpsToken::Literal(query) => Some(query),
|
||||||
|
@ -207,7 +185,6 @@ impl MpsOpFactory<SimpleSqlStatement> for SimpleSqlStatementFactory {
|
||||||
MpsToken::Literal("literal".into()),
|
MpsToken::Literal("literal".into()),
|
||||||
tokens,
|
tokens,
|
||||||
)?;
|
)?;
|
||||||
assert_token_raw(MpsToken::CloseBracket, tokens)?;
|
|
||||||
Ok(SimpleSqlStatement {
|
Ok(SimpleSqlStatement {
|
||||||
query: literal,
|
query: literal,
|
||||||
mode: QueryMode::from_name(mode_name)?,
|
mode: QueryMode::from_name(mode_name)?,
|
||||||
|
@ -218,16 +195,9 @@ impl MpsOpFactory<SimpleSqlStatement> for SimpleSqlStatementFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BoxedMpsOpFactory for SimpleSqlStatementFactory {
|
pub type SimpleSqlStatementFactory = MpsFunctionStatementFactory<SimpleSqlStatement, SimpleSqlFunctionFactory>;
|
||||||
fn build_op_boxed(
|
|
||||||
&self,
|
|
||||||
tokens: &mut VecDeque<MpsToken>,
|
|
||||||
dict: &MpsLanguageDictionary,
|
|
||||||
) -> Result<Box<dyn MpsOp>, SyntaxError> {
|
|
||||||
self.build_box(tokens, dict)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_op_boxed(&self, tokens: &VecDeque<MpsToken>) -> bool {
|
#[inline(always)]
|
||||||
self.is_op(tokens)
|
pub fn simple_sql_function_factory() -> SimpleSqlStatementFactory {
|
||||||
}
|
SimpleSqlStatementFactory::new(SimpleSqlFunctionFactory)
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ fn execute_single_line(line: &str, should_be_emtpy: bool, should_complete: bool)
|
||||||
count += 1;
|
count += 1;
|
||||||
if count > 100 {
|
if count > 100 {
|
||||||
if should_complete {
|
if should_complete {
|
||||||
continue;
|
continue; // skip println, but still check for errors
|
||||||
} else {
|
} else {
|
||||||
println!("Got 100 items, stopping to avoid infinite loop");
|
println!("Got 100 items, stopping to avoid infinite loop");
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue