2019-06-03 07:11:21 +02:00
|
|
|
use crate::object::Primitive;
|
2019-05-28 08:45:18 +02:00
|
|
|
use crate::parser::ast;
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
crate fn evaluate_expr(expr: &ast::Expression, scope: &Scope) -> Result<Value, ShellError> {
|
|
|
|
use ast::*;
|
2019-06-06 08:34:59 +02:00
|
|
|
match &expr.expr {
|
|
|
|
RawExpression::Call(_) => Err(ShellError::unimplemented("Evaluating call expression")),
|
|
|
|
RawExpression::Leaf(l) => Ok(evaluate_leaf(l)),
|
|
|
|
RawExpression::Parenthesized(p) => evaluate_expr(&p.expr, scope),
|
|
|
|
RawExpression::Flag(f) => Ok(Value::Primitive(Primitive::String(f.print()))),
|
|
|
|
RawExpression::Block(b) => evaluate_block(&b, scope),
|
|
|
|
RawExpression::Path(p) => evaluate_path(&p, scope),
|
|
|
|
RawExpression::Binary(b) => evaluate_binary(b, scope),
|
|
|
|
RawExpression::VariableReference(r) => evaluate_reference(r, scope),
|
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),
|
2019-05-30 06:19:46 +02:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn evaluate_binary(binary: &ast::Binary, scope: &Scope) -> Result<Value, ShellError> {
|
|
|
|
let left = evaluate_expr(&binary.left, scope)?;
|
|
|
|
let right = evaluate_expr(&binary.right, scope)?;
|
|
|
|
|
2019-06-06 08:34:59 +02:00
|
|
|
match left.compare(&binary.operator, &right) {
|
2019-05-28 08:45:18 +02:00
|
|
|
Some(v) => Ok(Value::boolean(v)),
|
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
|
|
|
))),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn evaluate_block(block: &ast::Block, _scope: &Scope) -> Result<Value, ShellError> {
|
|
|
|
Ok(Value::block(block.expr.clone()))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn evaluate_path(path: &ast::Path, scope: &Scope) -> Result<Value, ShellError> {
|
|
|
|
let head = path.head();
|
|
|
|
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() {
|
2019-06-06 08:34:59 +02:00
|
|
|
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
|
|
|
}
|
|
|
|
Some(v) => value = v,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(value.copy())
|
|
|
|
}
|