mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 22:47:43 +02:00
Move most of the root package into a subcrate. (#1445)
This improves incremental build time when working on what was previously the root package. For example, previously all plugins would be rebuilt with a change to `src/commands/classified/external.rs`, but now only `nu-cli` will have to be rebuilt (and anything that depends on it).
This commit is contained in:
57
crates/nu-cli/src/evaluate/evaluate_args.rs
Normal file
57
crates/nu-cli/src/evaluate/evaluate_args.rs
Normal file
@ -0,0 +1,57 @@
|
||||
// TODO: Temporary redirect
|
||||
use crate::context::CommandRegistry;
|
||||
use crate::evaluate::evaluate_baseline_expr;
|
||||
use indexmap::IndexMap;
|
||||
use nu_errors::ShellError;
|
||||
use nu_parser::hir;
|
||||
use nu_protocol::{EvaluatedArgs, Scope, UntaggedValue, Value};
|
||||
use nu_source::Text;
|
||||
|
||||
pub(crate) fn evaluate_args(
|
||||
call: &hir::Call,
|
||||
registry: &CommandRegistry,
|
||||
scope: &Scope,
|
||||
source: &Text,
|
||||
) -> Result<EvaluatedArgs, ShellError> {
|
||||
let positional: Result<Option<Vec<_>>, _> = call
|
||||
.positional
|
||||
.as_ref()
|
||||
.map(|p| {
|
||||
p.iter()
|
||||
.map(|e| evaluate_baseline_expr(e, registry, scope, source))
|
||||
.collect()
|
||||
})
|
||||
.transpose();
|
||||
|
||||
let positional = positional?;
|
||||
|
||||
let named: Result<Option<IndexMap<String, Value>>, ShellError> = call
|
||||
.named
|
||||
.as_ref()
|
||||
.map(|n| {
|
||||
let mut results = IndexMap::new();
|
||||
|
||||
for (name, value) in n.named.iter() {
|
||||
match value {
|
||||
hir::NamedValue::PresentSwitch(tag) => {
|
||||
results.insert(name.clone(), UntaggedValue::boolean(true).into_value(tag));
|
||||
}
|
||||
hir::NamedValue::Value(expr) => {
|
||||
results.insert(
|
||||
name.clone(),
|
||||
evaluate_baseline_expr(expr, registry, scope, source)?,
|
||||
);
|
||||
}
|
||||
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
||||
Ok(results)
|
||||
})
|
||||
.transpose();
|
||||
|
||||
let named = named?;
|
||||
|
||||
Ok(EvaluatedArgs::new(positional, named))
|
||||
}
|
185
crates/nu-cli/src/evaluate/evaluator.rs
Normal file
185
crates/nu-cli/src/evaluate/evaluator.rs
Normal file
@ -0,0 +1,185 @@
|
||||
use crate::context::CommandRegistry;
|
||||
use crate::data::base::Block;
|
||||
use crate::evaluate::operator::apply_operator;
|
||||
use crate::prelude::*;
|
||||
use log::trace;
|
||||
use nu_errors::{ArgumentError, ShellError};
|
||||
use nu_parser::hir::{self, Expression, SpannedExpression};
|
||||
use nu_protocol::{
|
||||
ColumnPath, Evaluate, Primitive, RangeInclusion, Scope, UnspannedPathMember, UntaggedValue,
|
||||
Value,
|
||||
};
|
||||
use nu_source::Text;
|
||||
|
||||
pub(crate) fn evaluate_baseline_expr(
|
||||
expr: &SpannedExpression,
|
||||
registry: &CommandRegistry,
|
||||
scope: &Scope,
|
||||
source: &Text,
|
||||
) -> Result<Value, ShellError> {
|
||||
let tag = Tag {
|
||||
span: expr.span,
|
||||
anchor: None,
|
||||
};
|
||||
match &expr.expr {
|
||||
Expression::Literal(literal) => Ok(evaluate_literal(literal, expr.span, source)),
|
||||
Expression::ExternalWord => Err(ShellError::argument_error(
|
||||
"Invalid external word".spanned(tag.span),
|
||||
ArgumentError::InvalidExternalWord,
|
||||
)),
|
||||
Expression::FilePath(path) => Ok(UntaggedValue::path(path.clone()).into_value(tag)),
|
||||
Expression::Synthetic(hir::Synthetic::String(s)) => {
|
||||
Ok(UntaggedValue::string(s).into_untagged_value())
|
||||
}
|
||||
Expression::Variable(var) => evaluate_reference(var, scope, source, tag),
|
||||
Expression::Command(_) => evaluate_command(tag, scope, source),
|
||||
Expression::ExternalCommand(external) => evaluate_external(external, scope, source),
|
||||
Expression::Binary(binary) => {
|
||||
let left = evaluate_baseline_expr(binary.left(), registry, scope, source)?;
|
||||
let right = evaluate_baseline_expr(binary.right(), registry, scope, source)?;
|
||||
|
||||
trace!("left={:?} right={:?}", left.value, right.value);
|
||||
|
||||
match apply_operator(**binary.op(), &left, &right) {
|
||||
Ok(result) => Ok(result.into_value(tag)),
|
||||
Err((left_type, right_type)) => Err(ShellError::coerce_error(
|
||||
left_type.spanned(binary.left().span),
|
||||
right_type.spanned(binary.right().span),
|
||||
)),
|
||||
}
|
||||
}
|
||||
Expression::Range(range) => {
|
||||
let left = range.left();
|
||||
let right = range.right();
|
||||
|
||||
let left = evaluate_baseline_expr(left, registry, scope, source)?;
|
||||
let right = evaluate_baseline_expr(right, registry, scope, source)?;
|
||||
let left_span = left.tag.span;
|
||||
let right_span = right.tag.span;
|
||||
|
||||
let left = (
|
||||
left.as_primitive()?.spanned(left_span),
|
||||
RangeInclusion::Inclusive,
|
||||
);
|
||||
let right = (
|
||||
right.as_primitive()?.spanned(right_span),
|
||||
RangeInclusion::Exclusive,
|
||||
);
|
||||
|
||||
Ok(UntaggedValue::range(left, right).into_value(tag))
|
||||
}
|
||||
Expression::List(list) => {
|
||||
let mut exprs = vec![];
|
||||
|
||||
for expr in list {
|
||||
let expr = evaluate_baseline_expr(expr, registry, scope, source)?;
|
||||
exprs.push(expr);
|
||||
}
|
||||
|
||||
Ok(UntaggedValue::Table(exprs).into_value(tag))
|
||||
}
|
||||
Expression::Block(block) => Ok(UntaggedValue::Block(Evaluate::new(Block::new(
|
||||
block.clone(),
|
||||
source.clone(),
|
||||
tag.clone(),
|
||||
)))
|
||||
.into_value(&tag)),
|
||||
Expression::Path(path) => {
|
||||
let value = evaluate_baseline_expr(path.head(), registry, scope, source)?;
|
||||
let mut item = value;
|
||||
|
||||
for member in path.tail() {
|
||||
let next = item.get_data_by_member(member);
|
||||
|
||||
match next {
|
||||
Err(err) => {
|
||||
let possibilities = item.data_descriptors();
|
||||
|
||||
if let UnspannedPathMember::String(name) = &member.unspanned {
|
||||
let mut possible_matches: Vec<_> = possibilities
|
||||
.iter()
|
||||
.map(|x| (natural::distance::levenshtein_distance(x, &name), x))
|
||||
.collect();
|
||||
|
||||
possible_matches.sort();
|
||||
|
||||
if !possible_matches.is_empty() {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Unknown column",
|
||||
format!("did you mean '{}'?", possible_matches[0].1),
|
||||
&tag,
|
||||
));
|
||||
} else {
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(next) => {
|
||||
item = next.clone().value.into_value(&tag);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Ok(item.value.into_value(tag))
|
||||
}
|
||||
Expression::Boolean(_boolean) => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate_literal(literal: &hir::Literal, span: Span, source: &Text) -> Value {
|
||||
match &literal {
|
||||
hir::Literal::ColumnPath(path) => {
|
||||
let members = path
|
||||
.iter()
|
||||
.map(|member| member.to_path_member(source))
|
||||
.collect();
|
||||
|
||||
UntaggedValue::Primitive(Primitive::ColumnPath(ColumnPath::new(members)))
|
||||
.into_value(span)
|
||||
}
|
||||
hir::Literal::Number(int) => match int {
|
||||
nu_parser::Number::Int(i) => UntaggedValue::int(i.clone()).into_value(span),
|
||||
nu_parser::Number::Decimal(d) => UntaggedValue::decimal(d.clone()).into_value(span),
|
||||
},
|
||||
hir::Literal::Size(int, unit) => unit.compute(&int).into_value(span),
|
||||
hir::Literal::String(tag) => UntaggedValue::string(tag.slice(source)).into_value(span),
|
||||
hir::Literal::GlobPattern(pattern) => UntaggedValue::pattern(pattern).into_value(span),
|
||||
hir::Literal::Bare => UntaggedValue::string(span.slice(source)).into_value(span),
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate_reference(
|
||||
name: &hir::Variable,
|
||||
scope: &Scope,
|
||||
source: &Text,
|
||||
tag: Tag,
|
||||
) -> Result<Value, ShellError> {
|
||||
trace!("Evaluating {:?} with Scope {:?}", name, scope);
|
||||
match name {
|
||||
hir::Variable::It(_) => Ok(scope.it.value.clone().into_value(tag)),
|
||||
hir::Variable::Other(inner) => match inner.slice(source) {
|
||||
x if x == "nu" => crate::evaluate::variables::nu(tag),
|
||||
x => Ok(scope
|
||||
.vars
|
||||
.get(x)
|
||||
.cloned()
|
||||
.unwrap_or_else(|| UntaggedValue::nothing().into_value(tag))),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate_external(
|
||||
external: &hir::ExternalCommand,
|
||||
_scope: &Scope,
|
||||
_source: &Text,
|
||||
) -> Result<Value, ShellError> {
|
||||
Err(ShellError::syntax_error(
|
||||
"Unexpected external command".spanned(*external.name()),
|
||||
))
|
||||
}
|
||||
|
||||
fn evaluate_command(tag: Tag, _scope: &Scope, _source: &Text) -> Result<Value, ShellError> {
|
||||
Err(ShellError::syntax_error(
|
||||
"Unexpected command".spanned(tag.span),
|
||||
))
|
||||
}
|
6
crates/nu-cli/src/evaluate/mod.rs
Normal file
6
crates/nu-cli/src/evaluate/mod.rs
Normal file
@ -0,0 +1,6 @@
|
||||
pub(crate) mod evaluate_args;
|
||||
pub(crate) mod evaluator;
|
||||
pub(crate) mod operator;
|
||||
pub(crate) mod variables;
|
||||
|
||||
pub(crate) use evaluator::evaluate_baseline_expr;
|
50
crates/nu-cli/src/evaluate/operator.rs
Normal file
50
crates/nu-cli/src/evaluate/operator.rs
Normal file
@ -0,0 +1,50 @@
|
||||
use crate::data::value;
|
||||
use nu_parser::CompareOperator;
|
||||
use nu_protocol::{Primitive, ShellTypeName, UntaggedValue, Value};
|
||||
use std::ops::Not;
|
||||
|
||||
pub fn apply_operator(
|
||||
op: CompareOperator,
|
||||
left: &Value,
|
||||
right: &Value,
|
||||
) -> Result<UntaggedValue, (&'static str, &'static str)> {
|
||||
match op {
|
||||
CompareOperator::Equal
|
||||
| CompareOperator::NotEqual
|
||||
| CompareOperator::LessThan
|
||||
| CompareOperator::GreaterThan
|
||||
| CompareOperator::LessThanOrEqual
|
||||
| CompareOperator::GreaterThanOrEqual => {
|
||||
value::compare_values(op, left, right).map(UntaggedValue::boolean)
|
||||
}
|
||||
CompareOperator::Contains => contains(left, right).map(UntaggedValue::boolean),
|
||||
CompareOperator::NotContains => contains(left, right)
|
||||
.map(Not::not)
|
||||
.map(UntaggedValue::boolean),
|
||||
}
|
||||
}
|
||||
|
||||
fn contains(
|
||||
left: &UntaggedValue,
|
||||
right: &UntaggedValue,
|
||||
) -> Result<bool, (&'static str, &'static str)> {
|
||||
match (left, right) {
|
||||
(
|
||||
UntaggedValue::Primitive(Primitive::String(l)),
|
||||
UntaggedValue::Primitive(Primitive::String(r)),
|
||||
) => Ok(l.contains(r)),
|
||||
(
|
||||
UntaggedValue::Primitive(Primitive::Line(l)),
|
||||
UntaggedValue::Primitive(Primitive::String(r)),
|
||||
) => Ok(l.contains(r)),
|
||||
(
|
||||
UntaggedValue::Primitive(Primitive::String(l)),
|
||||
UntaggedValue::Primitive(Primitive::Line(r)),
|
||||
) => Ok(l.contains(r)),
|
||||
(
|
||||
UntaggedValue::Primitive(Primitive::Line(l)),
|
||||
UntaggedValue::Primitive(Primitive::Line(r)),
|
||||
) => Ok(l.contains(r)),
|
||||
_ => Err((left.type_name(), right.type_name())),
|
||||
}
|
||||
}
|
31
crates/nu-cli/src/evaluate/variables.rs
Normal file
31
crates/nu-cli/src/evaluate/variables.rs
Normal file
@ -0,0 +1,31 @@
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{TaggedDictBuilder, UntaggedValue, Value};
|
||||
use nu_source::Tag;
|
||||
|
||||
pub fn nu(tag: impl Into<Tag>) -> Result<Value, ShellError> {
|
||||
let tag = tag.into();
|
||||
|
||||
let mut nu_dict = TaggedDictBuilder::new(&tag);
|
||||
|
||||
let mut dict = TaggedDictBuilder::new(&tag);
|
||||
for v in std::env::vars() {
|
||||
if v.0 != "PATH" && v.0 != "Path" {
|
||||
dict.insert_untagged(v.0, UntaggedValue::string(v.1));
|
||||
}
|
||||
}
|
||||
nu_dict.insert_value("env", dict.into_value());
|
||||
|
||||
let config = crate::data::config::read(&tag, &None)?;
|
||||
nu_dict.insert_value("config", UntaggedValue::row(config).into_value(&tag));
|
||||
|
||||
let mut table = vec![];
|
||||
let path = std::env::var_os("PATH");
|
||||
if let Some(paths) = path {
|
||||
for path in std::env::split_paths(&paths) {
|
||||
table.push(UntaggedValue::path(path).into_value(&tag));
|
||||
}
|
||||
}
|
||||
nu_dict.insert_value("path", UntaggedValue::table(&table).into_value(&tag));
|
||||
|
||||
Ok(nu_dict.into_value())
|
||||
}
|
Reference in New Issue
Block a user