nushell/src/evaluate/evaluator.rs

117 lines
3.3 KiB
Rust
Raw Normal View History

2019-06-03 07:11:21 +02:00
use crate::object::Primitive;
2019-05-28 08:45:18 +02:00
use crate::parser::ast;
2019-06-08 00:35:07 +02:00
use crate::parser::lexer::Spanned;
2019-05-28 08:45:18 +02:00
use crate::prelude::*;
use derive_new::new;
2019-06-03 07:11:21 +02:00
use indexmap::IndexMap;
2019-05-28 08:45:18 +02:00
#[derive(new)]
crate struct Scope {
it: Value,
2019-06-03 07:11:21 +02:00
#[new(default)]
vars: IndexMap<String, Value>,
2019-05-28 08:45:18 +02:00
}
impl Scope {
crate fn empty() -> Scope {
Scope {
it: Value::nothing(),
2019-06-03 07:11:21 +02:00
vars: IndexMap::new(),
2019-05-28 08:45:18 +02:00
}
}
}
2019-06-08 00:35:07 +02:00
crate fn evaluate_expr(
expr: &ast::Expression,
scope: &Scope,
) -> Result<Spanned<Value>, ShellError> {
2019-05-28 08:45:18 +02:00
use ast::*;
match &expr.expr {
RawExpression::Call(_) => Err(ShellError::unimplemented("Evaluating call expression")),
2019-06-08 00:35:07 +02:00
RawExpression::Leaf(l) => Ok(Spanned::from_item(evaluate_leaf(l), expr.span.clone())),
RawExpression::Parenthesized(p) => evaluate_expr(&p.expr, scope),
2019-06-08 00:35:07 +02:00
RawExpression::Flag(f) => Ok(Spanned::from_item(
Value::Primitive(Primitive::String(f.print())),
expr.span.clone(),
)),
RawExpression::Block(b) => evaluate_block(&b, scope),
RawExpression::Path(p) => evaluate_path(&p, scope),
RawExpression::Binary(b) => evaluate_binary(b, scope),
2019-06-08 00:35:07 +02:00
RawExpression::VariableReference(r) => {
evaluate_reference(r, scope).map(|x| Spanned::from_item(x, expr.span.clone()))
}
2019-05-28 08:45:18 +02:00
}
}
fn evaluate_leaf(leaf: &ast::Leaf) -> Value {
use ast::*;
match leaf {
Leaf::String(s) => Value::string(s),
Leaf::Bare(path) => Value::string(path.to_string()),
2019-05-28 08:45:18 +02:00
Leaf::Boolean(b) => Value::boolean(*b),
Leaf::Int(i) => Value::int(*i),
2019-06-02 18:28:40 +02:00
Leaf::Unit(i, unit) => unit.compute(*i),
2019-05-28 08:45:18 +02:00
}
}
fn evaluate_reference(r: &ast::Variable, scope: &Scope) -> Result<Value, ShellError> {
use ast::Variable::*;
match r {
It => Ok(scope.it.copy()),
2019-06-03 07:11:21 +02:00
Other(s) => Ok(scope
.vars
.get(s)
.map(|v| v.copy())
.unwrap_or_else(|| Value::nothing())),
2019-05-28 08:45:18 +02:00
}
}
2019-06-08 00:35:07 +02:00
fn evaluate_binary(binary: &ast::Binary, scope: &Scope) -> Result<Spanned<Value>, ShellError> {
2019-05-28 08:45:18 +02:00
let left = evaluate_expr(&binary.left, scope)?;
let right = evaluate_expr(&binary.right, scope)?;
match left.compare(&binary.operator, &right) {
2019-06-08 00:35:07 +02:00
Some(v) => Ok(Spanned::from_item(
Value::boolean(v),
binary.operator.span.clone(),
)),
2019-06-03 07:11:21 +02:00
None => Err(ShellError::TypeError(format!(
"Can't compare {} and {}",
left.type_name(),
right.type_name()
2019-05-28 08:45:18 +02:00
))),
}
}
2019-06-08 00:35:07 +02:00
fn evaluate_block(block: &ast::Block, _scope: &Scope) -> Result<Spanned<Value>, ShellError> {
Ok(Spanned::from_item(
Value::block(block.expr.clone()),
block.expr.span.clone(),
))
2019-05-28 08:45:18 +02:00
}
2019-06-08 00:35:07 +02:00
fn evaluate_path(path: &ast::Path, scope: &Scope) -> Result<Spanned<Value>, ShellError> {
2019-05-28 08:45:18 +02:00
let head = path.head();
2019-06-08 00:35:07 +02:00
let mut value = evaluate_expr(head, scope)?;
2019-06-03 07:11:21 +02:00
let mut seen = vec![];
2019-05-28 08:45:18 +02:00
for name in path.tail() {
let next = value.get_data_by_key(&name.item);
seen.push(name.item.clone());
2019-05-28 08:45:18 +02:00
match next {
None => {
2019-06-03 07:11:21 +02:00
return Err(ShellError::MissingProperty {
expr: path.print(),
subpath: itertools::join(seen, "."),
});
2019-05-28 08:45:18 +02:00
}
2019-06-08 00:35:07 +02:00
Some(v) => value = Spanned::from_item(v.copy(), name.span.clone()),
2019-05-28 08:45:18 +02:00
}
}
2019-06-08 00:35:07 +02:00
Ok(value)
2019-05-28 08:45:18 +02:00
}