diff --git a/lykiadb-lang/src/lib.rs b/lykiadb-lang/src/lib.rs index 34f8e0ce..c089b878 100644 --- a/lykiadb-lang/src/lib.rs +++ b/lykiadb-lang/src/lib.rs @@ -1,4 +1,7 @@ -use std::{fmt::{Display, Formatter, Result}, sync::Arc}; +use std::{ + fmt::{Display, Formatter, Result}, + sync::Arc, +}; use ast::expr::Expr; use rustc_hash::FxHashMap; @@ -76,4 +79,4 @@ impl Display for Identifier { fn fmt(&self, f: &mut Formatter) -> Result { write!(f, "{}", self.name) } -} \ No newline at end of file +} diff --git a/lykiadb-lang/src/parser/mod.rs b/lykiadb-lang/src/parser/mod.rs index 38c75457..1f5c77ed 100644 --- a/lykiadb-lang/src/parser/mod.rs +++ b/lykiadb-lang/src/parser/mod.rs @@ -542,18 +542,12 @@ impl<'a> Parser<'a> { match (&expr_conj_fst, &expr_conj_sec) { (Some(SqlKeyword(Between)), None) => self.cmp_between(left, false), - (Some(SqlKeyword(Not)), Some(SqlKeyword(Between))) => { - self.cmp_between(left, true) - } + (Some(SqlKeyword(Not)), Some(SqlKeyword(Between))) => self.cmp_between(left, true), _ => Ok(expr), } } - fn cmp_between( - &mut self, - subject: Box, - falsy: bool, - ) -> ParseResult> { + fn cmp_between(&mut self, subject: Box, falsy: bool) -> ParseResult> { let lower = self.term()?; self.expected(skw!(And))?; @@ -563,7 +557,11 @@ impl<'a> Parser<'a> { subject: subject.clone(), lower, upper: upper.clone(), - kind: if falsy { RangeKind::NotBetween } else { RangeKind::Between }, + kind: if falsy { + RangeKind::NotBetween + } else { + RangeKind::Between + }, span: subject.get_span().merge(&upper.get_span()), id: self.get_expr_id(), })) diff --git a/lykiadb-lang/src/parser/program.rs b/lykiadb-lang/src/parser/program.rs index 12377200..50f82e5b 100644 --- a/lykiadb-lang/src/parser/program.rs +++ b/lykiadb-lang/src/parser/program.rs @@ -4,7 +4,9 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use crate::{ - ast::{expr::Expr, stmt::Stmt}, tokenizer::scanner::Scanner, Locals, Scopes + ast::{expr::Expr, stmt::Stmt}, + tokenizer::scanner::Scanner, + Locals, Scopes, }; use super::{resolver::Resolver, ParseError, ParseResult, Parser}; diff --git a/lykiadb-server/src/engine/interpreter.rs b/lykiadb-server/src/engine/interpreter.rs index bf0945b3..4356fd1d 100644 --- a/lykiadb-server/src/engine/interpreter.rs +++ b/lykiadb-server/src/engine/interpreter.rs @@ -18,7 +18,7 @@ use crate::plan::planner::Planner; use crate::util::{alloc_shared, Shared}; use crate::value::callable::{Callable, CallableKind, Function, Stateful}; use crate::value::environment::{EnvId, Environment}; -use crate::value::{RV, eval::eval_binary}; +use crate::value::{eval::eval_binary, RV}; use std::sync::Arc; use std::vec; @@ -182,7 +182,7 @@ pub struct Interpreter { impl Interpreter { pub fn new(out: Option>, with_stdlib: bool) -> Interpreter { let mut env_man = Environment::new(); - if with_stdlib { + if with_stdlib { let native_fns = stdlib(out.clone()); let env = env_man.top(); @@ -475,7 +475,11 @@ impl VisitorMut for Interpreter { closure: self.env, }; - let callable = RV::Callable(Callable::new(Some(parameters.len()), CallableKind::Generic, fun.into())); + let callable = RV::Callable(Callable::new( + Some(parameters.len()), + CallableKind::Generic, + fun.into(), + )); if name.is_some() { // TODO(vck): Callable shouldn't be cloned here @@ -493,7 +497,7 @@ impl VisitorMut for Interpreter { upper, subject, kind, - span:_ , + span: _, id: _, } => { let lower_eval = self.visit_expr(lower)?; @@ -507,9 +511,9 @@ impl VisitorMut for Interpreter { let max_num = lower_num.max(upper_num); match kind { - RangeKind::Between => Ok(RV::Bool( - min_num <= subject_num && subject_num <= max_num, - )), + RangeKind::Between => { + Ok(RV::Bool(min_num <= subject_num && subject_num <= max_num)) + } RangeKind::NotBetween => { Ok(RV::Bool(min_num > subject_num || subject_num > max_num)) } @@ -722,7 +726,10 @@ pub mod test_helpers { pub fn get_runtime() -> (Shared, Runtime) { let out = alloc_shared(Output::new()); - (out.clone(), Runtime::new(RuntimeMode::File, Interpreter::new(Some(out), true))) + ( + out.clone(), + Runtime::new(RuntimeMode::File, Interpreter::new(Some(out), true)), + ) } pub fn exec_assert(code: &str, output: Vec) { diff --git a/lykiadb-server/src/engine/mod.rs b/lykiadb-server/src/engine/mod.rs index c77f09d2..807e7f87 100644 --- a/lykiadb-server/src/engine/mod.rs +++ b/lykiadb-server/src/engine/mod.rs @@ -23,10 +23,7 @@ pub enum RuntimeMode { impl Runtime { pub fn new(mode: RuntimeMode, interpreter: Interpreter) -> Runtime { - Runtime { - mode, - interpreter, - } + Runtime { mode, interpreter } } pub fn ast(&mut self, source: &str) -> Result { diff --git a/lykiadb-server/src/engine/stdlib/mod.rs b/lykiadb-server/src/engine/stdlib/mod.rs index 8722b807..ae048f99 100644 --- a/lykiadb-server/src/engine/stdlib/mod.rs +++ b/lykiadb-server/src/engine/stdlib/mod.rs @@ -2,7 +2,10 @@ use rustc_hash::FxHashMap; use crate::{ util::{alloc_shared, Shared}, - value::{callable::{Callable, CallableKind, Function}, RV}, + value::{ + callable::{Callable, CallableKind, Function}, + RV, + }, }; use self::{ @@ -28,20 +31,22 @@ pub fn stdlib(out: Option>) -> FxHashMap { benchmark_namespace.insert( "fib".to_owned(), - RV::Callable(Callable::new(Some(1), CallableKind::Generic, Function::Lambda { function: nt_fib })), + RV::Callable(Callable::new( + Some(1), + CallableKind::Generic, + Function::Lambda { function: nt_fib }, + )), ); json_namespace.insert( "stringify".to_owned(), - RV::Callable( - Callable::new( - Some(1), - CallableKind::Generic, - Function::Lambda { - function: nt_json_encode, - } - ) - ), + RV::Callable(Callable::new( + Some(1), + CallableKind::Generic, + Function::Lambda { + function: nt_json_encode, + }, + )), ); json_namespace.insert( @@ -51,16 +56,16 @@ pub fn stdlib(out: Option>) -> FxHashMap { CallableKind::Generic, Function::Lambda { function: nt_json_decode, - }), - ), + }, + )), ); time_namespace.insert( "clock".to_owned(), RV::Callable(Callable::new( - Some(0), + Some(0), CallableKind::Generic, - Function::Lambda { function: nt_clock } + Function::Lambda { function: nt_clock }, )), ); @@ -69,7 +74,11 @@ pub fn stdlib(out: Option>) -> FxHashMap { test_namespace.insert( "out".to_owned(), - RV::Callable(Callable::new(None, CallableKind::Generic, Function::Stateful(out.unwrap().clone()))), + RV::Callable(Callable::new( + None, + CallableKind::Generic, + Function::Stateful(out.unwrap().clone()), + )), ); std.insert( @@ -86,7 +95,11 @@ pub fn stdlib(out: Option>) -> FxHashMap { std.insert("Time".to_owned(), RV::Object(alloc_shared(time_namespace))); std.insert( "print".to_owned(), - RV::Callable(Callable::new(None, CallableKind::Generic, Function::Lambda { function: nt_print })), + RV::Callable(Callable::new( + None, + CallableKind::Generic, + Function::Lambda { function: nt_print }, + )), ); std diff --git a/lykiadb-server/src/plan/mod.rs b/lykiadb-server/src/plan/mod.rs index 95668b92..84cf74f5 100644 --- a/lykiadb-server/src/plan/mod.rs +++ b/lykiadb-server/src/plan/mod.rs @@ -113,10 +113,27 @@ impl Node { source._fmt_recursive(f, indent + 1) } Node::Scan { source, filter } => { - write!(f, "{}- scan [{} as {}]{}", indent_str, source.name, source.alias.as_ref().unwrap_or(&source.name), Self::NEWLINE) + write!( + f, + "{}- scan [{} as {}]{}", + indent_str, + source.name, + source.alias.as_ref().unwrap_or(&source.name), + Self::NEWLINE + ) } - Node::Compound { source, operator, right } => { - write!(f, "{}- compound [{:?}]{}", indent_str, operator, Self::NEWLINE)?; + Node::Compound { + source, + operator, + right, + } => { + write!( + f, + "{}- compound [{:?}]{}", + indent_str, + operator, + Self::NEWLINE + )?; source._fmt_recursive(f, indent + 1)?; right._fmt_recursive(f, indent + 1) } @@ -134,7 +151,14 @@ impl Node { right, constraint, } => { - write!(f, "{}- join [{:?}, {}]:{}", indent_str, join_type, constraint.as_ref().unwrap(), Self::NEWLINE)?; + write!( + f, + "{}- join [{:?}, {}]:{}", + indent_str, + join_type, + constraint.as_ref().unwrap(), + Self::NEWLINE + )?; left._fmt_recursive(f, indent + 1)?; right._fmt_recursive(f, indent + 1) } @@ -145,6 +169,6 @@ impl Node { impl Display for Node { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self._fmt_recursive(f, 0) - } -} \ No newline at end of file + self._fmt_recursive(f, 0) + } +} diff --git a/lykiadb-server/src/plan/planner.rs b/lykiadb-server/src/plan/planner.rs index 928a26e5..02684dda 100644 --- a/lykiadb-server/src/plan/planner.rs +++ b/lykiadb-server/src/plan/planner.rs @@ -1,7 +1,11 @@ -use crate::{engine::interpreter::{Interpreter, HaltReason}, util::Shared}; +use crate::{ + engine::interpreter::{HaltReason, Interpreter}, + util::Shared, +}; use lykiadb_lang::ast::{ expr::Expr, - sql::{SqlFrom, SqlJoinType, SqlSelect, SqlSelectCore}, visitor::VisitorMut + sql::{SqlFrom, SqlJoinType, SqlSelect, SqlSelectCore}, + visitor::VisitorMut, }; use super::{Node, Plan}; @@ -11,9 +15,7 @@ pub struct Planner<'a> { impl<'a> Planner<'a> { pub fn new(interpreter: &'a mut Interpreter) -> Planner { - Planner { - interpreter - } + Planner { interpreter } } pub fn build(&mut self, expr: &Expr) -> Result { @@ -45,10 +47,10 @@ impl<'a> Planner<'a> { } } if let Some(compound) = &core.compound { - node = Node::Compound { + node = Node::Compound { source: Box::new(node), operator: compound.operator.clone(), - right: Box::new(self.build_select_core(&compound.core)?) + right: Box::new(self.build_select_core(&compound.core)?), } } // GROUP BY @@ -61,12 +63,28 @@ impl<'a> Planner<'a> { let mut node: Node = self.build_select_core(&query.core)?; // TODO(vck): ORDER BY - + if let Some(limit) = &query.limit { if let Some(offset) = &limit.offset { - node = Node::Offset { source: Box::new(node), offset: self.interpreter.visit_expr(&offset)?.as_number().expect("Offset is not correct").floor() as usize } + node = Node::Offset { + source: Box::new(node), + offset: self + .interpreter + .visit_expr(&offset)? + .as_number() + .expect("Offset is not correct") + .floor() as usize, + } + } + node = Node::Limit { + source: Box::new(node), + limit: self + .interpreter + .visit_expr(&limit.count)? + .as_number() + .expect("Limit is not correct") + .floor() as usize, } - node = Node::Limit { source: Box::new(node), limit: self.interpreter.visit_expr(&limit.count)?.as_number().expect("Limit is not correct").floor() as usize } } Ok(node) @@ -113,11 +131,9 @@ impl<'a> Planner<'a> { } } - pub mod test_helpers { use lykiadb_lang::{ast::stmt::Stmt, parser::program::Program}; - use crate::engine::interpreter::Interpreter; use super::Planner; diff --git a/lykiadb-server/src/value/callable.rs b/lykiadb-server/src/value/callable.rs index 88a7a8a0..3bdfade5 100644 --- a/lykiadb-server/src/value/callable.rs +++ b/lykiadb-server/src/value/callable.rs @@ -1,9 +1,12 @@ -use std::sync::Arc; -use std::fmt::{Debug, Display, Formatter}; -use lykiadb_lang::ast::stmt::Stmt; -use crate::{engine::interpreter::{HaltReason, Interpreter}, util::Shared}; use super::environment::EnvId; use super::RV; +use crate::{ + engine::interpreter::{HaltReason, Interpreter}, + util::Shared, +}; +use lykiadb_lang::ast::stmt::Stmt; +use std::fmt::{Debug, Display, Formatter}; +use std::sync::Arc; #[derive(Debug, Clone)] pub enum CallableKind { diff --git a/lykiadb-server/src/value/eval.rs b/lykiadb-server/src/value/eval.rs index 50d62212..61e48589 100644 --- a/lykiadb-server/src/value/eval.rs +++ b/lykiadb-server/src/value/eval.rs @@ -1,7 +1,7 @@ +use super::RV; use lykiadb_lang::ast::expr::Operation; use std::ops; use std::sync::Arc; -use super::RV; impl PartialEq for RV { fn eq(&self, other: &Self) -> bool { diff --git a/lykiadb-server/src/value/mod.rs b/lykiadb-server/src/value/mod.rs index 7db8aae5..b0ab59ba 100644 --- a/lykiadb-server/src/value/mod.rs +++ b/lykiadb-server/src/value/mod.rs @@ -1,15 +1,15 @@ -use std::sync::{Arc, RwLock}; +use rustc_hash::FxHashMap; use serde::ser::{SerializeMap, SerializeSeq}; use serde::{Deserialize, Serialize}; -use rustc_hash::FxHashMap; +use std::sync::{Arc, RwLock}; use crate::util::alloc_shared; use crate::util::Shared; use callable::Callable; +pub mod callable; pub mod environment; pub mod eval; -pub mod callable; #[derive(Debug, Clone)] pub enum RV { @@ -73,15 +73,11 @@ impl RV { pub fn is_in(&self, other: &RV) -> RV { match (self, other) { - (RV::Str(lhs), RV::Str(rhs)) => { - RV::Bool(rhs.contains(lhs.as_str())) - } - (lhs, RV::Array(rhs)) => { - RV::Bool(rhs.read().unwrap().contains(&lhs)) - } + (RV::Str(lhs), RV::Str(rhs)) => RV::Bool(rhs.contains(lhs.as_str())), + (lhs, RV::Array(rhs)) => RV::Bool(rhs.read().unwrap().contains(&lhs)), (RV::Str(key), RV::Object(map)) => { RV::Bool(map.read().unwrap().contains_key(key.as_str())) - }, + } _ => RV::Bool(false), } } @@ -91,7 +87,6 @@ impl RV { } } - impl Serialize for RV { fn serialize(&self, serializer: S) -> Result where @@ -114,14 +109,12 @@ impl Serialize for RV { } RV::Object(obj) => { let mut map = serializer.serialize_map(None).unwrap(); - let arr = (obj as &RwLock>) - .read() - .unwrap(); + let arr = (obj as &RwLock>).read().unwrap(); for (key, value) in arr.iter() { map.serialize_entry(key, value)?; } map.end() - }, + } _ => serializer.serialize_none(), } } @@ -155,4 +148,3 @@ impl<'de> Deserialize<'de> for RV { } } } - diff --git a/lykiadb-server/tests/tests.rs b/lykiadb-server/tests/tests.rs index 0c02f139..4bb203b4 100644 --- a/lykiadb-server/tests/tests.rs +++ b/lykiadb-server/tests/tests.rs @@ -3,8 +3,8 @@ mod runtime; mod util; mod planner { - use test_each_file::test_each_file; use crate::util::run_test; + use test_each_file::test_each_file; test_each_file! { in "lykiadb-server/tests/planner" => run_test } } diff --git a/lykiadb-server/tests/util.rs b/lykiadb-server/tests/util.rs index d8272ff0..b19e8319 100644 --- a/lykiadb-server/tests/util.rs +++ b/lykiadb-server/tests/util.rs @@ -22,9 +22,13 @@ pub fn run_test(input: &str) { for part in parts[1..].iter() { let directives_and_input = part.trim(); - let directives_end = directives_and_input.find('>').unwrap_or(directives_and_input.len()); - let rest = directives_and_input[directives_end+1..].trim().to_string(); + let directives_end = directives_and_input + .find('>') + .unwrap_or(directives_and_input.len()); + let rest = directives_and_input[directives_end + 1..] + .trim() + .to_string(); let io_parts: Vec<&str> = rest.split("---").collect(); - expect_plan(&io_parts[0].trim(),&io_parts[1].trim()); + expect_plan(&io_parts[0].trim(), &io_parts[1].trim()); } -} \ No newline at end of file +}