Evaluator, MVP
This commit is contained in:
parent
55ec870bc8
commit
db4f632bd4
16
src/cli.rs
16
src/cli.rs
|
@ -6,7 +6,7 @@ use crate::commands::classified::{
|
||||||
};
|
};
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
crate use crate::errors::ShellError;
|
crate use crate::errors::ShellError;
|
||||||
use crate::evaluate::{evaluate_expr, Scope};
|
use crate::evaluate::Scope;
|
||||||
crate use crate::format::{EntriesListView, GenericView};
|
crate use crate::format::{EntriesListView, GenericView};
|
||||||
use crate::object::Value;
|
use crate::object::Value;
|
||||||
use crate::parser::{ParsedCommand, Pipeline};
|
use crate::parser::{ParsedCommand, Pipeline};
|
||||||
|
@ -56,7 +56,7 @@ pub async fn cli() -> Result<(), Box<Error>> {
|
||||||
command("reject", reject::reject),
|
command("reject", reject::reject),
|
||||||
command("to-array", to_array::to_array),
|
command("to-array", to_array::to_array),
|
||||||
command("to-json", to_json::to_json),
|
command("to-json", to_json::to_json),
|
||||||
command("where", where_::r#where),
|
Arc::new(Where),
|
||||||
command("sort-by", sort_by::sort_by),
|
command("sort-by", sort_by::sort_by),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -278,18 +278,18 @@ fn classify_command(
|
||||||
let command_name = &command.name[..];
|
let command_name = &command.name[..];
|
||||||
let args = &command.args;
|
let args = &command.args;
|
||||||
|
|
||||||
let arg_list: Result<Vec<Value>, _> = args
|
|
||||||
.iter()
|
|
||||||
.map(|i| evaluate_expr(i, &Scope::empty()))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
match command_name {
|
match command_name {
|
||||||
other => match context.has_command(command_name) {
|
other => match context.has_command(command_name) {
|
||||||
true => {
|
true => {
|
||||||
let command = context.get_command(command_name);
|
let command = context.get_command(command_name);
|
||||||
|
let config = command.config();
|
||||||
|
let scope = Scope::empty();
|
||||||
|
|
||||||
|
let args = config.evaluate_args(args.iter(), &scope)?;
|
||||||
|
|
||||||
Ok(ClassifiedCommand::Internal(InternalCommand {
|
Ok(ClassifiedCommand::Internal(InternalCommand {
|
||||||
command,
|
command,
|
||||||
args: arg_list?,
|
args,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
false => {
|
false => {
|
||||||
|
|
|
@ -20,3 +20,4 @@ crate mod where_;
|
||||||
|
|
||||||
crate use command::command;
|
crate use command::command;
|
||||||
crate use to_array::stream_to_array;
|
crate use to_array::stream_to_array;
|
||||||
|
crate use where_::Where;
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
use crate::evaluate::Scope;
|
|
||||||
use crate::parser::CommandConfig;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use bytes::{BufMut, BytesMut};
|
use bytes::{BufMut, BytesMut};
|
||||||
use futures_codec::{Decoder, Encoder, Framed};
|
use futures_codec::{Decoder, Encoder, Framed};
|
||||||
|
@ -111,40 +109,6 @@ impl InternalCommand {
|
||||||
crate fn name(&self) -> &str {
|
crate fn name(&self) -> &str {
|
||||||
self.command.name()
|
self.command.name()
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn evaluate_args(
|
|
||||||
&self,
|
|
||||||
exprs: Vec<ast::Expression>,
|
|
||||||
scope: &Scope,
|
|
||||||
) -> Result<Vec<Value>, ShellError> {
|
|
||||||
let CommandConfig {
|
|
||||||
name,
|
|
||||||
mandatory_positional,
|
|
||||||
optional_positional,
|
|
||||||
rest_positional,
|
|
||||||
named,
|
|
||||||
} = self.command.config();
|
|
||||||
|
|
||||||
let mut args = exprs.into_iter();
|
|
||||||
let mut evaluated = vec![];
|
|
||||||
|
|
||||||
for param in mandatory_positional {
|
|
||||||
let arg = match args.next() {
|
|
||||||
None => {
|
|
||||||
return Err(ShellError::string(&format!(
|
|
||||||
"Missing mandatory argument: {}",
|
|
||||||
param.name()
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(arg) => param.evaluate(arg, scope),
|
|
||||||
};
|
|
||||||
|
|
||||||
evaluated.push(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
crate struct ExternalCommand {
|
crate struct ExternalCommand {
|
||||||
|
|
|
@ -1,7 +1,29 @@
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::object::base::find;
|
use crate::parser::registry::PositionalType;
|
||||||
|
use crate::parser::CommandConfig;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub struct Where;
|
||||||
|
|
||||||
|
impl Command for Where {
|
||||||
|
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
|
r#where(args)
|
||||||
|
}
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"where"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn config(&self) -> CommandConfig {
|
||||||
|
CommandConfig {
|
||||||
|
name: self.name().to_string(),
|
||||||
|
mandatory_positional: vec![PositionalType::Block("condition".to_string())],
|
||||||
|
optional_positional: vec![],
|
||||||
|
rest_positional: false,
|
||||||
|
named: indexmap::IndexMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn r#where(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn r#where(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
if args.args.is_empty() {
|
if args.args.is_empty() {
|
||||||
return Err(ShellError::string("select requires a field"));
|
return Err(ShellError::string("select requires a field"));
|
||||||
|
@ -14,20 +36,13 @@ pub fn r#where(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let result = block.invoke(&item);
|
let result = block.invoke(&item);
|
||||||
|
|
||||||
let return_value = match result {
|
let return_value = match result {
|
||||||
Err(err) => {
|
Err(err) => Some(ReturnValue::Value(Value::Error(Box::new(err)))),
|
||||||
println!("{:?}", err);
|
|
||||||
Some(ReturnValue::Value(Value::Error(Box::new(err))))
|
|
||||||
}
|
|
||||||
Ok(v) if v.is_true() => Some(ReturnValue::Value(item.copy())),
|
Ok(v) if v.is_true() => Some(ReturnValue::Value(item.copy())),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
futures::future::ready(return_value)
|
futures::future::ready(return_value)
|
||||||
// futures::future::ready(as_bool)
|
|
||||||
// futures::future::ready(block.invoke(&item).
|
|
||||||
});
|
});
|
||||||
// .map(|item| )
|
|
||||||
// .map(|item| ReturnValue::Value(item.copy()));
|
|
||||||
|
|
||||||
Ok(objects.boxed())
|
Ok(objects.boxed())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use crate::object::base as obj;
|
|
||||||
use crate::parser::ast;
|
use crate::parser::ast;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
|
|
|
@ -37,7 +37,6 @@ impl RenderView for GenericView<'value> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Error(e) => {
|
Value::Error(e) => {
|
||||||
// println!("ERROR: {:?}", e);
|
|
||||||
host.stdout(&format!("{:?}", e));
|
host.stdout(&format!("{:?}", e));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -208,20 +208,11 @@ impl Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn is_intish(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
Value::Primitive(Primitive::Int(i)) => true,
|
|
||||||
// TODO: this should definitely be more general with better errors
|
|
||||||
Value::Primitive(Primitive::Bytes(b)) if *b <= std::i64::MAX as u128 => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
crate fn as_i64(&self) -> Result<i64, ShellError> {
|
crate fn as_i64(&self) -> Result<i64, ShellError> {
|
||||||
match self {
|
match self {
|
||||||
Value::Primitive(Primitive::Int(i)) => Ok(*i),
|
Value::Primitive(Primitive::Int(i)) => Ok(*i),
|
||||||
// TODO: this should definitely be more general with better errors
|
|
||||||
Value::Primitive(Primitive::Bytes(b)) if *b <= std::i64::MAX as u128 => Ok(*b as i64),
|
Value::Primitive(Primitive::Bytes(b)) if *b <= std::i64::MAX as u128 => Ok(*b as i64),
|
||||||
|
// TODO: this should definitely be more general with better errors
|
||||||
other => Err(ShellError::string(format!(
|
other => Err(ShellError::string(format!(
|
||||||
"Expected integer, got {:?}",
|
"Expected integer, got {:?}",
|
||||||
other
|
other
|
||||||
|
@ -255,7 +246,7 @@ impl Value {
|
||||||
crate fn is_true(&self) -> bool {
|
crate fn is_true(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Value::Primitive(Primitive::Boolean(true)) => true,
|
Value::Primitive(Primitive::Boolean(true)) => true,
|
||||||
other => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,13 +332,13 @@ crate fn reject_fields(obj: &Value, fields: &[String]) -> crate::object::Diction
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
crate fn find(obj: &Value, field: &str, op: &Operator, rhs: &Value) -> bool {
|
crate fn find(obj: &Value, field: &str, op: &Operator, rhs: &Value) -> bool {
|
||||||
let descs = obj.data_descriptors();
|
let descs = obj.data_descriptors();
|
||||||
match descs.iter().find(|d| d.name.is_string(field)) {
|
match descs.iter().find(|d| d.name.is_string(field)) {
|
||||||
None => false,
|
None => false,
|
||||||
Some(desc) => {
|
Some(desc) => {
|
||||||
let v = obj.get_data(desc).borrow().copy();
|
let v = obj.get_data(desc).borrow().copy();
|
||||||
//println!("'{:?}' '{:?}' '{:?}'", v, op, rhs);
|
|
||||||
|
|
||||||
match v {
|
match v {
|
||||||
Value::Primitive(Primitive::Boolean(b)) => match (op, rhs) {
|
Value::Primitive(Primitive::Boolean(b)) => match (op, rhs) {
|
||||||
|
|
|
@ -139,6 +139,8 @@ impl Variable {
|
||||||
pub enum Leaf {
|
pub enum Leaf {
|
||||||
String(String),
|
String(String),
|
||||||
Bare(String),
|
Bare(String),
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
Int(i64),
|
Int(i64),
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,22 +9,18 @@ pub Pipeline: Pipeline = {
|
||||||
}
|
}
|
||||||
|
|
||||||
Command: ParsedCommand = {
|
Command: ParsedCommand = {
|
||||||
<command:RawBareWord> <expr:Expr*> => ParsedCommand::new(command, expr)
|
<command:RawBareWord> <expr:Expr*> => ParsedCommand::new(command, expr),
|
||||||
|
<command:RawBareWord> <expr:BinaryExpression> => ParsedCommand::new(command, vec![expr]),
|
||||||
}
|
}
|
||||||
|
|
||||||
Leaf: Expression = {
|
Leaf: Expression = {
|
||||||
<String> => Expression::Leaf(Leaf::String(<>)),
|
<String> => Expression::Leaf(Leaf::String(<>)),
|
||||||
<Num> => Expression::Leaf(Leaf::Int(<>)),
|
<Num> => Expression::Leaf(Leaf::Int(<>)),
|
||||||
<Variable> => Expression::VariableReference(<>),
|
<Variable> => Expression::VariableReference(<>),
|
||||||
<RawBareWord> => match <>.as_ref() {
|
|
||||||
"$true" => Expression::Leaf(Leaf::Boolean(true)),
|
|
||||||
"$false" => Expression::Leaf(Leaf::Boolean(false)),
|
|
||||||
_ => Expression::Leaf(Leaf::Bare(<>)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BinaryExpression: Expression = {
|
BinaryExpression: Expression = {
|
||||||
<left:PathExpression> <op:Operator> <right:Leaf> => Expression::Binary(Box::new(Binary::new(left, op, right))),
|
<left:Expr> <op:Operator> <right:Leaf> => Expression::Binary(Box::new(Binary::new(left, op, right))),
|
||||||
}
|
}
|
||||||
|
|
||||||
Parenthesized: Expression = {
|
Parenthesized: Expression = {
|
||||||
|
@ -52,6 +48,7 @@ PathExpression: Expression = {
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr: Expression = {
|
Expr: Expression = {
|
||||||
|
<RawBareWord> => Expression::Leaf(Leaf::Bare(<>)),
|
||||||
<PathExpression>
|
<PathExpression>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -3,6 +3,7 @@ use crate::prelude::*;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum NamedType {
|
pub enum NamedType {
|
||||||
Switch(String),
|
Switch(String),
|
||||||
Single(String),
|
Single(String),
|
||||||
|
@ -10,6 +11,8 @@ pub enum NamedType {
|
||||||
Block(String),
|
Block(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub enum PositionalType {
|
pub enum PositionalType {
|
||||||
Value(String),
|
Value(String),
|
||||||
Block(String),
|
Block(String),
|
||||||
|
@ -25,8 +28,8 @@ impl PositionalType {
|
||||||
|
|
||||||
crate fn evaluate(&self, arg: ast::Expression, scope: &Scope) -> Result<Value, ShellError> {
|
crate fn evaluate(&self, arg: ast::Expression, scope: &Scope) -> Result<Value, ShellError> {
|
||||||
match self {
|
match self {
|
||||||
PositionalType::Value(s) => evaluate_expr(&arg, scope),
|
PositionalType::Value(_) => evaluate_expr(&arg, scope),
|
||||||
PositionalType::Block(s) => match arg {
|
PositionalType::Block(_) => match arg {
|
||||||
ast::Expression::Block(b) => Ok(Value::block(b.expr)),
|
ast::Expression::Block(b) => Ok(Value::block(b.expr)),
|
||||||
ast::Expression::Binary(b) => {
|
ast::Expression::Binary(b) => {
|
||||||
if let Some(s) = b.left.as_string() {
|
if let Some(s) = b.left.as_string() {
|
||||||
|
@ -50,7 +53,7 @@ impl PositionalType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[derive(Debug)]
|
||||||
pub struct CommandConfig {
|
pub struct CommandConfig {
|
||||||
crate name: String,
|
crate name: String,
|
||||||
crate mandatory_positional: Vec<PositionalType>,
|
crate mandatory_positional: Vec<PositionalType>,
|
||||||
|
@ -59,6 +62,51 @@ pub struct CommandConfig {
|
||||||
crate named: IndexMap<String, NamedType>,
|
crate named: IndexMap<String, NamedType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CommandConfig {
|
||||||
|
crate fn evaluate_args(
|
||||||
|
&self,
|
||||||
|
mut args: impl Iterator<Item = &'expr ast::Expression>,
|
||||||
|
scope: &Scope,
|
||||||
|
) -> Result<Vec<Value>, ShellError> {
|
||||||
|
let mut results: Vec<Value> = vec![];
|
||||||
|
|
||||||
|
for param in &self.mandatory_positional {
|
||||||
|
let arg = args.next();
|
||||||
|
|
||||||
|
let value = match arg {
|
||||||
|
None => {
|
||||||
|
return Err(ShellError::string(format!(
|
||||||
|
"expected mandatory positional argument {}",
|
||||||
|
param.name()
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(arg) => param.evaluate(arg.clone(), scope)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
results.push(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.rest_positional {
|
||||||
|
let rest: Result<Vec<Value>, _> =
|
||||||
|
args.map(|i| evaluate_expr(i, &Scope::empty())).collect();
|
||||||
|
results.extend(rest?);
|
||||||
|
} else {
|
||||||
|
match args.next() {
|
||||||
|
None => {}
|
||||||
|
Some(_) => return Err(ShellError::string("Too many arguments")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(results)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
crate fn signature(&self) -> String {
|
||||||
|
format!("TODO")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait CommandRegistry {
|
pub trait CommandRegistry {
|
||||||
fn get(&self, name: &str) -> CommandConfig;
|
fn get(&self, name: &str) -> CommandConfig;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user