Evaluator, MVP

This commit is contained in:
Yehuda Katz 2019-05-27 23:19:00 -07:00
parent 55ec870bc8
commit db4f632bd4
11 changed files with 593 additions and 534 deletions

View File

@ -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 => {

View File

@ -20,3 +20,4 @@ crate mod where_;
crate use command::command;
crate use to_array::stream_to_array;
crate use where_::Where;

View File

@ -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 {

View File

@ -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())
}

View File

@ -1,4 +1,3 @@
use crate::object::base as obj;
use crate::parser::ast;
use crate::prelude::*;
use derive_new::new;

View File

@ -37,7 +37,6 @@ impl RenderView for GenericView<'value> {
}
Value::Error(e) => {
// println!("ERROR: {:?}", e);
host.stdout(&format!("{:?}", e));
Ok(())
}

View File

@ -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) {

View File

@ -139,6 +139,8 @@ impl Variable {
pub enum Leaf {
String(String),
Bare(String),
#[allow(unused)]
Boolean(bool),
Int(i64),
}

View File

@ -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

View File

@ -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;
}