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;
|
||||
crate use crate::errors::ShellError;
|
||||
use crate::evaluate::{evaluate_expr, Scope};
|
||||
use crate::evaluate::Scope;
|
||||
crate use crate::format::{EntriesListView, GenericView};
|
||||
use crate::object::Value;
|
||||
use crate::parser::{ParsedCommand, Pipeline};
|
||||
|
@ -56,7 +56,7 @@ pub async fn cli() -> Result<(), Box<Error>> {
|
|||
command("reject", reject::reject),
|
||||
command("to-array", to_array::to_array),
|
||||
command("to-json", to_json::to_json),
|
||||
command("where", where_::r#where),
|
||||
Arc::new(Where),
|
||||
command("sort-by", sort_by::sort_by),
|
||||
]);
|
||||
}
|
||||
|
@ -278,18 +278,18 @@ fn classify_command(
|
|||
let command_name = &command.name[..];
|
||||
let args = &command.args;
|
||||
|
||||
let arg_list: Result<Vec<Value>, _> = args
|
||||
.iter()
|
||||
.map(|i| evaluate_expr(i, &Scope::empty()))
|
||||
.collect();
|
||||
|
||||
match command_name {
|
||||
other => match context.has_command(command_name) {
|
||||
true => {
|
||||
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 {
|
||||
command,
|
||||
args: arg_list?,
|
||||
args,
|
||||
}))
|
||||
}
|
||||
false => {
|
||||
|
|
|
@ -20,3 +20,4 @@ crate mod where_;
|
|||
|
||||
crate use command::command;
|
||||
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 bytes::{BufMut, BytesMut};
|
||||
use futures_codec::{Decoder, Encoder, Framed};
|
||||
|
@ -111,40 +109,6 @@ impl InternalCommand {
|
|||
crate fn name(&self) -> &str {
|
||||
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 {
|
||||
|
|
|
@ -1,7 +1,29 @@
|
|||
use crate::errors::ShellError;
|
||||
use crate::object::base::find;
|
||||
use crate::parser::registry::PositionalType;
|
||||
use crate::parser::CommandConfig;
|
||||
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> {
|
||||
if args.args.is_empty() {
|
||||
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 return_value = match result {
|
||||
Err(err) => {
|
||||
println!("{:?}", err);
|
||||
Some(ReturnValue::Value(Value::Error(Box::new(err))))
|
||||
}
|
||||
Err(err) => Some(ReturnValue::Value(Value::Error(Box::new(err)))),
|
||||
Ok(v) if v.is_true() => Some(ReturnValue::Value(item.copy())),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
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())
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use crate::object::base as obj;
|
||||
use crate::parser::ast;
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
|
|
|
@ -37,7 +37,6 @@ impl RenderView for GenericView<'value> {
|
|||
}
|
||||
|
||||
Value::Error(e) => {
|
||||
// println!("ERROR: {:?}", e);
|
||||
host.stdout(&format!("{:?}", e));
|
||||
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> {
|
||||
match self {
|
||||
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),
|
||||
// TODO: this should definitely be more general with better errors
|
||||
other => Err(ShellError::string(format!(
|
||||
"Expected integer, got {:?}",
|
||||
other
|
||||
|
@ -255,7 +246,7 @@ impl Value {
|
|||
crate fn is_true(&self) -> bool {
|
||||
match self {
|
||||
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
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
crate fn find(obj: &Value, field: &str, op: &Operator, rhs: &Value) -> bool {
|
||||
let descs = obj.data_descriptors();
|
||||
match descs.iter().find(|d| d.name.is_string(field)) {
|
||||
None => false,
|
||||
Some(desc) => {
|
||||
let v = obj.get_data(desc).borrow().copy();
|
||||
//println!("'{:?}' '{:?}' '{:?}'", v, op, rhs);
|
||||
|
||||
match v {
|
||||
Value::Primitive(Primitive::Boolean(b)) => match (op, rhs) {
|
||||
|
|
|
@ -139,6 +139,8 @@ impl Variable {
|
|||
pub enum Leaf {
|
||||
String(String),
|
||||
Bare(String),
|
||||
|
||||
#[allow(unused)]
|
||||
Boolean(bool),
|
||||
Int(i64),
|
||||
}
|
||||
|
|
|
@ -9,22 +9,18 @@ pub Pipeline: Pipeline = {
|
|||
}
|
||||
|
||||
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 = {
|
||||
<String> => Expression::Leaf(Leaf::String(<>)),
|
||||
<Num> => Expression::Leaf(Leaf::Int(<>)),
|
||||
<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 = {
|
||||
<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 = {
|
||||
|
@ -52,6 +48,7 @@ PathExpression: Expression = {
|
|||
}
|
||||
|
||||
Expr: Expression = {
|
||||
<RawBareWord> => Expression::Leaf(Leaf::Bare(<>)),
|
||||
<PathExpression>
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -3,6 +3,7 @@ use crate::prelude::*;
|
|||
use indexmap::IndexMap;
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug)]
|
||||
pub enum NamedType {
|
||||
Switch(String),
|
||||
Single(String),
|
||||
|
@ -10,6 +11,8 @@ pub enum NamedType {
|
|||
Block(String),
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PositionalType {
|
||||
Value(String),
|
||||
Block(String),
|
||||
|
@ -25,8 +28,8 @@ impl PositionalType {
|
|||
|
||||
crate fn evaluate(&self, arg: ast::Expression, scope: &Scope) -> Result<Value, ShellError> {
|
||||
match self {
|
||||
PositionalType::Value(s) => evaluate_expr(&arg, scope),
|
||||
PositionalType::Block(s) => match arg {
|
||||
PositionalType::Value(_) => evaluate_expr(&arg, scope),
|
||||
PositionalType::Block(_) => match arg {
|
||||
ast::Expression::Block(b) => Ok(Value::block(b.expr)),
|
||||
ast::Expression::Binary(b) => {
|
||||
if let Some(s) = b.left.as_string() {
|
||||
|
@ -50,7 +53,7 @@ impl PositionalType {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug)]
|
||||
pub struct CommandConfig {
|
||||
crate name: String,
|
||||
crate mandatory_positional: Vec<PositionalType>,
|
||||
|
@ -59,6 +62,51 @@ pub struct CommandConfig {
|
|||
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 {
|
||||
fn get(&self, name: &str) -> CommandConfig;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user