mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 13:36:07 +02:00
Extract nu_source into a crate
This commit extracts Tag, Span, Text, as well as source-related debug facilities into a new crate called nu_source. This change is much bigger than one might have expected because the previous code relied heavily on implementing inherent methods on `Tagged<T>` and `Spanned<T>`, which is no longer possible. As a result, this change creates more concrete types instead of using `Tagged<T>`. One notable example: Tagged<Value> became Value, and Value became UntaggedValue. This change clarifies the intent of the code in many places, but it does make it a big change.
This commit is contained in:
@ -1,23 +1,24 @@
|
||||
use crate::data::base::Block;
|
||||
use crate::errors::ArgumentError;
|
||||
use crate::parser::hir::path::{ColumnPath, RawPathMember};
|
||||
use crate::parser::hir::path::{ColumnPath, UnspannedPathMember};
|
||||
use crate::parser::{
|
||||
hir::{self, Expression, RawExpression},
|
||||
CommandRegistry, Text,
|
||||
CommandRegistry,
|
||||
};
|
||||
use crate::prelude::*;
|
||||
use crate::TaggedDictBuilder;
|
||||
use indexmap::IndexMap;
|
||||
use log::trace;
|
||||
use nu_source::Text;
|
||||
use std::fmt;
|
||||
|
||||
pub struct Scope {
|
||||
it: Tagged<Value>,
|
||||
vars: IndexMap<String, Tagged<Value>>,
|
||||
it: Value,
|
||||
vars: IndexMap<String, Value>,
|
||||
}
|
||||
|
||||
impl Scope {
|
||||
pub fn new(it: Tagged<Value>) -> Scope {
|
||||
pub fn new(it: Value) -> Scope {
|
||||
Scope {
|
||||
it,
|
||||
vars: IndexMap::new(),
|
||||
@ -28,8 +29,8 @@ impl Scope {
|
||||
impl fmt::Display for Scope {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_map()
|
||||
.entry(&"$it", &format!("{:?}", self.it.item))
|
||||
.entries(self.vars.iter().map(|(k, v)| (k, &v.item)))
|
||||
.entry(&"$it", &format!("{:?}", self.it.value))
|
||||
.entries(self.vars.iter().map(|(k, v)| (k, &v.value)))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@ -37,12 +38,12 @@ impl fmt::Display for Scope {
|
||||
impl Scope {
|
||||
pub(crate) fn empty() -> Scope {
|
||||
Scope {
|
||||
it: Value::nothing().tagged_unknown(),
|
||||
it: UntaggedValue::nothing().into_untagged_value(),
|
||||
vars: IndexMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn it_value(value: Tagged<Value>) -> Scope {
|
||||
pub(crate) fn it_value(value: Value) -> Scope {
|
||||
Scope {
|
||||
it: value,
|
||||
vars: IndexMap::new(),
|
||||
@ -55,20 +56,20 @@ pub(crate) fn evaluate_baseline_expr(
|
||||
registry: &CommandRegistry,
|
||||
scope: &Scope,
|
||||
source: &Text,
|
||||
) -> Result<Tagged<Value>, ShellError> {
|
||||
) -> Result<Value, ShellError> {
|
||||
let tag = Tag {
|
||||
span: expr.span,
|
||||
anchor: None,
|
||||
};
|
||||
match &expr.item {
|
||||
RawExpression::Literal(literal) => Ok(evaluate_literal(literal.tagged(tag), source)),
|
||||
match &expr.expr {
|
||||
RawExpression::Literal(literal) => Ok(evaluate_literal(literal, source)),
|
||||
RawExpression::ExternalWord => Err(ShellError::argument_error(
|
||||
"Invalid external word".spanned(tag.span),
|
||||
ArgumentError::InvalidExternalWord,
|
||||
)),
|
||||
RawExpression::FilePath(path) => Ok(Value::path(path.clone()).tagged(tag)),
|
||||
RawExpression::FilePath(path) => Ok(UntaggedValue::path(path.clone()).into_value(tag)),
|
||||
RawExpression::Synthetic(hir::Synthetic::String(s)) => {
|
||||
Ok(Value::string(s).tagged_unknown())
|
||||
Ok(UntaggedValue::string(s).into_untagged_value())
|
||||
}
|
||||
RawExpression::Variable(var) => evaluate_reference(var, scope, source, tag),
|
||||
RawExpression::Command(_) => evaluate_command(tag, scope, source),
|
||||
@ -77,10 +78,10 @@ pub(crate) fn evaluate_baseline_expr(
|
||||
let left = evaluate_baseline_expr(binary.left(), registry, scope, source)?;
|
||||
let right = evaluate_baseline_expr(binary.right(), registry, scope, source)?;
|
||||
|
||||
trace!("left={:?} right={:?}", left.item, right.item);
|
||||
trace!("left={:?} right={:?}", left.value, right.value);
|
||||
|
||||
match left.compare(binary.op(), &*right) {
|
||||
Ok(result) => Ok(Value::boolean(result).tagged(tag)),
|
||||
match left.compare(binary.op(), &right) {
|
||||
Ok(result) => Ok(UntaggedValue::boolean(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),
|
||||
@ -95,10 +96,13 @@ pub(crate) fn evaluate_baseline_expr(
|
||||
exprs.push(expr);
|
||||
}
|
||||
|
||||
Ok(Value::Table(exprs).tagged(tag))
|
||||
Ok(UntaggedValue::Table(exprs).into_value(tag))
|
||||
}
|
||||
RawExpression::Block(block) => {
|
||||
Ok(Value::Block(Block::new(block.clone(), source.clone(), tag.clone())).tagged(&tag))
|
||||
Ok(
|
||||
UntaggedValue::Block(Block::new(block.clone(), source.clone(), tag.clone()))
|
||||
.into_value(&tag),
|
||||
)
|
||||
}
|
||||
RawExpression::Path(path) => {
|
||||
let value = evaluate_baseline_expr(path.head(), registry, scope, source)?;
|
||||
@ -111,7 +115,7 @@ pub(crate) fn evaluate_baseline_expr(
|
||||
Err(err) => {
|
||||
let possibilities = item.data_descriptors();
|
||||
|
||||
if let RawPathMember::String(name) = &member.item {
|
||||
if let UnspannedPathMember::String(name) = &member.unspanned {
|
||||
let mut possible_matches: Vec<_> = possibilities
|
||||
.iter()
|
||||
.map(|x| (natural::distance::levenshtein_distance(x, &name), x))
|
||||
@ -131,35 +135,40 @@ pub(crate) fn evaluate_baseline_expr(
|
||||
}
|
||||
}
|
||||
Ok(next) => {
|
||||
item = next.clone().item.tagged(&tag);
|
||||
item = next.clone().value.into_value(&tag);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Ok(item.item().clone().tagged(tag))
|
||||
Ok(item.value.clone().into_value(tag))
|
||||
}
|
||||
RawExpression::Boolean(_boolean) => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate_literal(literal: Tagged<&hir::Literal>, source: &Text) -> Tagged<Value> {
|
||||
let result = match literal.item {
|
||||
hir::Literal::ColumnPath(path) => {
|
||||
fn evaluate_literal(literal: &hir::Literal, source: &Text) -> Value {
|
||||
match &literal.literal {
|
||||
hir::RawLiteral::ColumnPath(path) => {
|
||||
let members = path
|
||||
.iter()
|
||||
.map(|member| member.to_path_member(source))
|
||||
.collect();
|
||||
|
||||
Value::Primitive(Primitive::ColumnPath(ColumnPath::new(members)))
|
||||
UntaggedValue::Primitive(Primitive::ColumnPath(ColumnPath::new(members)))
|
||||
.into_value(&literal.span)
|
||||
}
|
||||
hir::Literal::Number(int) => int.into(),
|
||||
hir::Literal::Size(int, unit) => unit.compute(int),
|
||||
hir::Literal::String(tag) => Value::string(tag.slice(source)),
|
||||
hir::Literal::GlobPattern(pattern) => Value::pattern(pattern),
|
||||
hir::Literal::Bare => Value::string(literal.tag().slice(source)),
|
||||
};
|
||||
|
||||
literal.map(|_| result)
|
||||
hir::RawLiteral::Number(int) => UntaggedValue::number(int.clone()).into_value(literal.span),
|
||||
hir::RawLiteral::Size(int, unit) => unit.compute(&int).into_value(literal.span),
|
||||
hir::RawLiteral::String(tag) => {
|
||||
UntaggedValue::string(tag.slice(source)).into_value(literal.span)
|
||||
}
|
||||
hir::RawLiteral::GlobPattern(pattern) => {
|
||||
UntaggedValue::pattern(pattern).into_value(literal.span)
|
||||
}
|
||||
hir::RawLiteral::Bare => {
|
||||
UntaggedValue::string(literal.span.slice(source)).into_value(literal.span)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate_reference(
|
||||
@ -167,41 +176,41 @@ fn evaluate_reference(
|
||||
scope: &Scope,
|
||||
source: &Text,
|
||||
tag: Tag,
|
||||
) -> Result<Tagged<Value>, ShellError> {
|
||||
) -> Result<Value, ShellError> {
|
||||
trace!("Evaluating {} with Scope {}", name, scope);
|
||||
match name {
|
||||
hir::Variable::It(_) => Ok(scope.it.item.clone().tagged(tag)),
|
||||
hir::Variable::It(_) => Ok(scope.it.value.clone().into_value(tag)),
|
||||
hir::Variable::Other(inner) => match inner.slice(source) {
|
||||
x if x == "nu:env" => {
|
||||
let mut dict = TaggedDictBuilder::new(&tag);
|
||||
for v in std::env::vars() {
|
||||
if v.0 != "PATH" && v.0 != "Path" {
|
||||
dict.insert(v.0, Value::string(v.1));
|
||||
dict.insert_untagged(v.0, UntaggedValue::string(v.1));
|
||||
}
|
||||
}
|
||||
Ok(dict.into_tagged_value())
|
||||
Ok(dict.into_value())
|
||||
}
|
||||
x if x == "nu:config" => {
|
||||
let config = crate::data::config::read(tag.clone(), &None)?;
|
||||
Ok(Value::row(config).tagged(tag))
|
||||
Ok(UntaggedValue::row(config).into_value(tag))
|
||||
}
|
||||
x if x == "nu:path" => {
|
||||
let mut table = vec![];
|
||||
match std::env::var_os("PATH") {
|
||||
Some(paths) => {
|
||||
for path in std::env::split_paths(&paths) {
|
||||
table.push(Value::path(path).tagged(&tag));
|
||||
table.push(UntaggedValue::path(path).into_value(&tag));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Ok(Value::table(&table).tagged(tag))
|
||||
Ok(UntaggedValue::table(&table).into_value(tag))
|
||||
}
|
||||
x => Ok(scope
|
||||
.vars
|
||||
.get(x)
|
||||
.map(|v| v.clone())
|
||||
.unwrap_or_else(|| Value::nothing().tagged(tag))),
|
||||
.unwrap_or_else(|| UntaggedValue::nothing().into_value(tag))),
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -210,13 +219,13 @@ fn evaluate_external(
|
||||
external: &hir::ExternalCommand,
|
||||
_scope: &Scope,
|
||||
_source: &Text,
|
||||
) -> Result<Tagged<Value>, ShellError> {
|
||||
) -> Result<Value, ShellError> {
|
||||
Err(ShellError::syntax_error(
|
||||
"Unexpected external command".spanned(*external.name()),
|
||||
))
|
||||
}
|
||||
|
||||
fn evaluate_command(tag: Tag, _scope: &Scope, _source: &Text) -> Result<Tagged<Value>, ShellError> {
|
||||
fn evaluate_command(tag: Tag, _scope: &Scope, _source: &Text) -> Result<Value, ShellError> {
|
||||
Err(ShellError::syntax_error(
|
||||
"Unexpected command".spanned(tag.span),
|
||||
))
|
||||
|
Reference in New Issue
Block a user