nushell/src/evaluate/evaluator.rs

107 lines
3.5 KiB
Rust
Raw Normal View History

2019-06-24 02:55:31 +02:00
use crate::errors::Description;
2019-06-22 03:36:57 +02:00
use crate::object::base::Block;
use crate::parser::{
hir::{self, Expression, RawExpression},
2019-06-22 16:08:53 +02:00
CommandRegistry, Spanned, Text,
2019-06-22 03:36:57 +02:00
};
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-22 03:36:57 +02:00
crate fn evaluate_baseline_expr(
expr: &Expression,
registry: &dyn CommandRegistry,
2019-06-08 00:35:07 +02:00
scope: &Scope,
2019-06-22 22:46:16 +02:00
source: &Text,
2019-06-08 00:35:07 +02:00
) -> Result<Spanned<Value>, ShellError> {
2019-06-22 03:36:57 +02:00
match &expr.item {
RawExpression::Literal(literal) => Ok(evaluate_literal(expr.copy_span(*literal), source)),
RawExpression::Variable(var) => evaluate_reference(var, scope, source),
RawExpression::Binary(binary) => {
let left = evaluate_baseline_expr(binary.left(), registry, scope, source)?;
let right = evaluate_baseline_expr(binary.right(), registry, scope, source)?;
2019-05-28 08:45:18 +02:00
2019-06-22 03:36:57 +02:00
match left.compare(binary.op(), &*right) {
2019-06-24 02:55:31 +02:00
Ok(result) => Ok(Spanned::from_item(Value::boolean(result), *expr.span())),
Err((left_type, right_type)) => Err(ShellError::CoerceError {
left: binary.left().copy_span(left_type),
right: binary.right().copy_span(right_type),
}),
2019-06-22 03:36:57 +02:00
}
}
RawExpression::Block(block) => Ok(Spanned::from_item(
Value::Block(Block::new(block.clone(), source.clone(), *expr.span())),
expr.span(),
2019-06-22 03:36:57 +02:00
)),
RawExpression::Path(path) => {
let value = evaluate_baseline_expr(path.head(), registry, scope, source)?;
2019-06-24 02:55:31 +02:00
let mut item = value;
2019-05-28 08:45:18 +02:00
2019-06-22 03:36:57 +02:00
for name in path.tail() {
2019-06-24 02:55:31 +02:00
let next = item.get_data_by_key(name);
2019-05-28 08:45:18 +02:00
2019-06-22 03:36:57 +02:00
match next {
2019-06-24 02:55:31 +02:00
None => {
return Err(ShellError::MissingProperty {
subpath: Description::from(item.spanned_type_name()),
expr: Description::from(name.clone()),
})
}
Some(next) => {
item =
Spanned::from_item(next.clone(), (expr.span().start, name.span().end))
}
2019-06-22 03:36:57 +02:00
};
}
2019-05-28 08:45:18 +02:00
2019-06-24 02:55:31 +02:00
Ok(Spanned::from_item(item.item().clone(), expr.span()))
2019-06-22 03:36:57 +02:00
}
RawExpression::Boolean(_boolean) => unimplemented!(),
2019-05-28 08:45:18 +02:00
}
}
2019-06-22 22:46:16 +02:00
fn evaluate_literal(literal: Spanned<hir::Literal>, source: &Text) -> Spanned<Value> {
2019-06-22 03:36:57 +02:00
let result = match literal.item {
hir::Literal::Integer(int) => Value::int(int),
2019-06-24 09:59:23 +02:00
hir::Literal::Size(int, unit) => unit.compute(int),
2019-06-22 03:36:57 +02:00
hir::Literal::String(span) => Value::string(span.slice(source)),
hir::Literal::Bare => Value::string(literal.span().slice(source)),
};
2019-05-28 08:45:18 +02:00
2019-06-22 03:36:57 +02:00
literal.map(|_| result)
2019-05-28 08:45:18 +02:00
}
2019-06-22 03:36:57 +02:00
fn evaluate_reference(
name: &hir::Variable,
scope: &Scope,
2019-06-22 22:46:16 +02:00
source: &Text,
2019-06-22 03:36:57 +02:00
) -> Result<Spanned<Value>, ShellError> {
match name {
hir::Variable::It(span) => Ok(Spanned::from_item(scope.it.copy(), span)),
hir::Variable::Other(span) => Ok(Spanned::from_item(
scope
.vars
.get(span.slice(source))
.map(|v| v.copy())
.unwrap_or_else(|| Value::nothing()),
span,
)),
2019-05-28 08:45:18 +02:00
}
}