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 03:36:57 +02:00
|
|
|
source: &str,
|
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) {
|
|
|
|
Some(result) => Ok(Spanned::from_item(Value::boolean(result), *expr.span())),
|
|
|
|
None => Err(ShellError::unimplemented(&format!(
|
|
|
|
"Comparison failure {:?}",
|
|
|
|
binary
|
|
|
|
))),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
RawExpression::Block(block) => Ok(Spanned::from_item(
|
|
|
|
Value::Block(Block::new(*block.clone(), Text::from(source))), // TODO: Pass Text around
|
|
|
|
block.span(),
|
|
|
|
)),
|
|
|
|
RawExpression::Path(path) => {
|
|
|
|
let value = evaluate_baseline_expr(path.head(), registry, scope, source)?;
|
|
|
|
let mut value = value.item();
|
2019-05-28 08:45:18 +02:00
|
|
|
|
2019-06-22 03:36:57 +02:00
|
|
|
for name in path.tail() {
|
|
|
|
let next = value.get_data_by_key(name);
|
2019-05-28 08:45:18 +02:00
|
|
|
|
2019-06-22 03:36:57 +02:00
|
|
|
match next {
|
|
|
|
None => return Err(ShellError::unimplemented("Invalid property from path")),
|
|
|
|
Some(next) => value = next,
|
|
|
|
};
|
|
|
|
}
|
2019-05-28 08:45:18 +02:00
|
|
|
|
2019-06-22 03:36:57 +02:00
|
|
|
Ok(Spanned::from_item(value.clone(), expr.span()))
|
|
|
|
}
|
|
|
|
RawExpression::Boolean(_boolean) => unimplemented!(),
|
2019-05-28 08:45:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-22 03:36:57 +02:00
|
|
|
fn evaluate_literal(literal: Spanned<hir::Literal>, source: &str) -> Spanned<Value> {
|
|
|
|
let result = match literal.item {
|
|
|
|
hir::Literal::Integer(int) => Value::int(int),
|
|
|
|
hir::Literal::Size(_int, _unit) => unimplemented!(),
|
|
|
|
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,
|
|
|
|
source: &str,
|
|
|
|
) -> 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
|
|
|
}
|
|
|
|
}
|