Evaluator MVP (#39)

Evaluator, MVP
This commit is contained in:
Yehuda Katz
2019-05-27 23:45:18 -07:00
committed by GitHub
parent d45750617b
commit d5255f6dbf
24 changed files with 2258 additions and 654 deletions

View File

@ -1,4 +1,5 @@
use derive_new::new;
use getset::Getters;
use std::str::FromStr;
use serde_derive::{Deserialize, Serialize};
@ -40,25 +41,106 @@ impl FromStr for Operator {
}
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub enum Expression {
Leaf(Leaf),
Binary(Binary),
Parenthesized(Box<Parenthesized>),
Block(Box<Block>),
Binary(Box<Binary>),
Path(Box<Path>),
VariableReference(Variable),
}
impl Expression {
crate fn print(&self) -> String {
match self {
Expression::Leaf(l) => l.print(),
Expression::Parenthesized(p) => p.print(),
Expression::Block(b) => b.print(),
Expression::VariableReference(r) => r.print(),
Expression::Path(p) => p.print(),
Expression::Binary(b) => b.print(),
}
}
crate fn as_string(&self) -> Option<String> {
match self {
Expression::Leaf(Leaf::String(s)) | Expression::Leaf(Leaf::Bare(s)) => {
Some(s.to_string())
}
_ => None,
}
}
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, new)]
pub struct Block {
crate expr: Expression,
}
impl Block {
fn print(&self) -> String {
format!("{{ {} }}", self.expr.print())
}
}
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, new)]
pub struct Parenthesized {
crate expr: Expression,
}
impl Parenthesized {
fn print(&self) -> String {
format!("({})", self.expr.print())
}
}
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Getters, new)]
pub struct Path {
#[get = "crate"]
head: Expression,
#[get = "crate"]
tail: Vec<String>,
}
impl Path {
crate fn print(&self) -> String {
let mut out = self.head.print();
for item in self.tail.iter() {
out.push_str(&format!(".{}", item));
}
out
}
}
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub enum Variable {
It,
True,
False,
Other(String),
}
impl Variable {
fn print(&self) -> String {
match self {
Variable::It => format!("$it"),
Variable::True => format!("$true"),
Variable::False => format!("$false"),
Variable::Other(s) => format!("${}", s),
}
}
}
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub enum Leaf {
String(String),
Bare(String),
#[allow(unused)]
Boolean(bool),
Int(i64),
}
@ -74,11 +156,11 @@ impl Leaf {
}
}
#[derive(Debug, Clone, new)]
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, new)]
pub struct Binary {
crate left: Leaf,
crate left: Expression,
crate operator: Operator,
crate right: Leaf,
crate right: Expression,
}
impl Binary {

View File

@ -1,6 +1,6 @@
use std::str::FromStr;
use crate::parser::tokens::*;
use byte_unit::Byte;
use crate::parser::ast::*;
grammar;
@ -10,12 +10,59 @@ 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(<>),
}
BinaryExpression: Expression = {
<left:Expr> <op:Operator> <right:Leaf> => Expression::Binary(Box::new(Binary::new(left, op, right))),
}
Parenthesized: Expression = {
"(" <Leaf> ")" => Expression::Parenthesized(Box::new(Parenthesized::new(<>))),
"(" <BinaryExpression> ")" => Expression::Parenthesized(Box::new(Parenthesized::new(<>))),
}
AtomicExpression: Expression = {
<Parenthesized>,
<Leaf>,
}
Block: Expression = {
"{" <AtomicExpression> "}" => Expression::Block(Box::new(Block::new(<>))),
"{" <BinaryExpression> "}" => Expression::Block(Box::new(Block::new(<>))),
}
WholeExpression: Expression = {
<AtomicExpression>,
<Block>,
}
PathExpression: Expression = {
<head:WholeExpression> <tail: ( "." <Member> )*> => Expression::Path(Box::new(Path::new(head, tail)))
}
Expr: Expression = {
<Leaf> => Expression::Leaf(<>),
<Binary> => Expression::Binary(<>),
<RawBareWord> => Expression::Leaf(Leaf::Bare(<>)),
<PathExpression>
}
Variable: Variable = {
"$true" => Variable::True,
"$false" => Variable::False,
"$it" => Variable::It,
"$" <RawBareWord> => Variable::Other(<>.to_string()),
}
Member: String = {
<RawBareWord>,
<String>
}
Operator: Operator = {
@ -27,10 +74,6 @@ Operator: Operator = {
">=" => Operator::GreaterThanOrEqual
}
Binary: Binary = {
<left:Leaf> <op:Operator> <right:Leaf> => Binary::new(left, op, right),
}
Flag: Flag = {
"-" <RawBareWord> => Flag::Shorthand(<>.to_string()),
"--" <RawBareWord> => Flag::Longhand(<>.to_string()),
@ -41,18 +84,7 @@ String: String = {
DQString,
}
Leaf: Leaf = {
<String> => Leaf::String(<>),
<Size> => Leaf::Int(<>),
<Num> => Leaf::Int(<>),
<RawBareWord> => match <>.as_ref() {
"true" => Leaf::Boolean(true),
"false" => Leaf::Boolean(false),
_ => Leaf::Bare(<>),
}
}
RawBareWord: String = <s:r#"[^0-9"'\-][^\s]*"#> => <>.to_string();
RawBareWord: String = <s:r#"[^0-9"'\-][^\s"']*"#> => <>.to_string();
DQString: String = <s:r#""([^"]|\\")*""#> => s[1..s.len() - 1].to_string();
SQString: String = <s:r#"'([^']|\\')*'"#> => s[1..s.len() - 1].to_string();
Num: i64 = <s:r"-?[0-9]+"> => i64::from_str(s).unwrap();

File diff suppressed because it is too large Load Diff

View File

@ -1,19 +1,110 @@
use crate::evaluate::{evaluate_expr, Scope};
use crate::prelude::*;
use indexmap::IndexMap;
#[allow(unused)]
pub enum CommandType {
Switch,
Single,
Array,
#[derive(Debug)]
pub enum NamedType {
Switch(String),
Single(String),
Array(String),
Block(String),
}
#[allow(unused)]
#[derive(Debug, Clone)]
pub enum PositionalType {
Value(String),
Block(String),
}
impl PositionalType {
crate fn name(&self) -> String {
match self {
PositionalType::Value(s) => s.clone(),
PositionalType::Block(s) => s.clone(),
}
}
crate fn evaluate(&self, arg: ast::Expression, scope: &Scope) -> Result<Value, ShellError> {
match self {
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() {
Ok(Value::block(ast::Expression::Binary(Box::new(
ast::Binary::new(
ast::Expression::Path(Box::new(ast::Path::new(
ast::Expression::VariableReference(ast::Variable::It),
vec![s],
))),
b.operator,
b.right,
),
))))
} else {
Ok(Value::block(ast::Expression::Binary(b)))
}
}
other => Ok(Value::block(other)), // other =>
},
}
}
}
#[derive(Debug)]
pub struct CommandConfig {
crate name: String,
crate mandatory_positional: Vec<String>,
crate optional_positional: Vec<String>,
crate mandatory_positional: Vec<PositionalType>,
crate optional_positional: Vec<PositionalType>,
crate rest_positional: bool,
crate named: IndexMap<String, CommandType>,
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 {