support parser info
This commit is contained in:
parent
67bd88535c
commit
dca2798d4d
|
@ -61,14 +61,13 @@ impl Command for OverlayUse {
|
||||||
call: &Call,
|
call: &Call,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let call = call.assert_ast_call()?; // FIXME
|
|
||||||
let mut name_arg: Spanned<String> = call.req(engine_state, caller_stack, 0)?;
|
let mut name_arg: Spanned<String> = call.req(engine_state, caller_stack, 0)?;
|
||||||
name_arg.item = trim_quotes_str(&name_arg.item).to_string();
|
name_arg.item = trim_quotes_str(&name_arg.item).to_string();
|
||||||
|
|
||||||
let maybe_origin_module_id =
|
let maybe_origin_module_id =
|
||||||
if let Some(overlay_expr) = call.get_parser_info("overlay_expr") {
|
if let Some(overlay_expr) = call.get_parser_info(caller_stack, "overlay_expr") {
|
||||||
if let Expr::Overlay(module_id) = &overlay_expr.expr {
|
if let Expr::Overlay(module_id) = &overlay_expr.expr {
|
||||||
module_id
|
module_id.clone()
|
||||||
} else {
|
} else {
|
||||||
return Err(ShellError::NushellFailedSpanned {
|
return Err(ShellError::NushellFailedSpanned {
|
||||||
msg: "Not an overlay".to_string(),
|
msg: "Not an overlay".to_string(),
|
||||||
|
@ -111,7 +110,7 @@ impl Command for OverlayUse {
|
||||||
// a) adding a new overlay
|
// a) adding a new overlay
|
||||||
// b) refreshing an active overlay (the origin module changed)
|
// b) refreshing an active overlay (the origin module changed)
|
||||||
|
|
||||||
let module = engine_state.get_module(*module_id);
|
let module = engine_state.get_module(module_id);
|
||||||
|
|
||||||
// Evaluate the export-env block (if any) and keep its environment
|
// Evaluate the export-env block (if any) and keep its environment
|
||||||
if let Some(block_id) = module.env_block {
|
if let Some(block_id) = module.env_block {
|
||||||
|
@ -119,7 +118,7 @@ impl Command for OverlayUse {
|
||||||
&name_arg.item,
|
&name_arg.item,
|
||||||
engine_state,
|
engine_state,
|
||||||
caller_stack,
|
caller_stack,
|
||||||
get_dirs_var_from_call(call),
|
get_dirs_var_from_call(caller_stack, call),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let block = engine_state.get_block(block_id);
|
let block = engine_state.get_block(block_id);
|
||||||
|
|
|
@ -54,11 +54,10 @@ This command is a parser keyword. For details, check:
|
||||||
call: &Call,
|
call: &Call,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let call = call.assert_ast_call()?; // FIXME
|
|
||||||
let Some(Expression {
|
let Some(Expression {
|
||||||
expr: Expr::ImportPattern(import_pattern),
|
expr: Expr::ImportPattern(import_pattern),
|
||||||
..
|
..
|
||||||
}) = call.get_parser_info("import_pattern")
|
}) = call.get_parser_info(caller_stack, "import_pattern")
|
||||||
else {
|
else {
|
||||||
return Err(ShellError::GenericError {
|
return Err(ShellError::GenericError {
|
||||||
error: "Unexpected import".into(),
|
error: "Unexpected import".into(),
|
||||||
|
@ -69,6 +68,9 @@ This command is a parser keyword. For details, check:
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Necessary so that we can modify the stack.
|
||||||
|
let import_pattern = import_pattern.clone();
|
||||||
|
|
||||||
if let Some(module_id) = import_pattern.head.id {
|
if let Some(module_id) = import_pattern.head.id {
|
||||||
// Add constants
|
// Add constants
|
||||||
for var_id in &import_pattern.constants {
|
for var_id in &import_pattern.constants {
|
||||||
|
@ -100,7 +102,7 @@ This command is a parser keyword. For details, check:
|
||||||
&module_arg_str,
|
&module_arg_str,
|
||||||
engine_state,
|
engine_state,
|
||||||
caller_stack,
|
caller_stack,
|
||||||
get_dirs_var_from_call(call),
|
get_dirs_var_from_call(caller_stack, call),
|
||||||
)?;
|
)?;
|
||||||
let maybe_parent = maybe_file_path
|
let maybe_parent = maybe_file_path
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
|
|
@ -48,12 +48,9 @@ impl Command for BytesBuild {
|
||||||
call: &Call,
|
call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let call = call.assert_ast_call()?; // FIXME
|
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
for val in call.rest_iter_flattened(0, |expr| {
|
|
||||||
let eval_expression = get_eval_expression(engine_state);
|
let eval_expression = get_eval_expression(engine_state);
|
||||||
eval_expression(engine_state, stack, expr)
|
for val in call.rest_iter_flattened(engine_state, stack, eval_expression, 0)? {
|
||||||
})? {
|
|
||||||
let val_span = val.span();
|
let val_span = val.span();
|
||||||
match val {
|
match val {
|
||||||
Value::Binary { mut val, .. } => output.append(&mut val),
|
Value::Binary { mut val, .. } => output.append(&mut val),
|
||||||
|
|
3
crates/nu-command/src/env/source_env.rs
vendored
3
crates/nu-command/src/env/source_env.rs
vendored
|
@ -45,7 +45,6 @@ impl Command for SourceEnv {
|
||||||
call: &Call,
|
call: &Call,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let call = call.assert_ast_call()?; // FIXME
|
|
||||||
let source_filename: Spanned<String> = call.req(engine_state, caller_stack, 0)?;
|
let source_filename: Spanned<String> = call.req(engine_state, caller_stack, 0)?;
|
||||||
|
|
||||||
// Note: this hidden positional is the block_id that corresponded to the 0th position
|
// Note: this hidden positional is the block_id that corresponded to the 0th position
|
||||||
|
@ -57,7 +56,7 @@ impl Command for SourceEnv {
|
||||||
&source_filename.item,
|
&source_filename.item,
|
||||||
engine_state,
|
engine_state,
|
||||||
caller_stack,
|
caller_stack,
|
||||||
get_dirs_var_from_call(call),
|
get_dirs_var_from_call(caller_stack, call),
|
||||||
)? {
|
)? {
|
||||||
PathBuf::from(&path)
|
PathBuf::from(&path)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -87,7 +87,7 @@ impl Command for NuCheck {
|
||||||
&path_str.item,
|
&path_str.item,
|
||||||
engine_state,
|
engine_state,
|
||||||
stack,
|
stack,
|
||||||
get_dirs_var_from_call(call.assert_ast_call()?), // FIXME
|
get_dirs_var_from_call(stack, call), // FIXME
|
||||||
) {
|
) {
|
||||||
Ok(path) => {
|
Ok(path) => {
|
||||||
if let Some(path) = path {
|
if let Some(path) = path {
|
||||||
|
|
|
@ -293,7 +293,21 @@ impl CallExt for ir::Call {
|
||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
name: &str,
|
name: &str,
|
||||||
) -> Result<T, ShellError> {
|
) -> Result<T, ShellError> {
|
||||||
todo!("req_parser_info is not yet implemented on ir::Call")
|
// FIXME: this depends on the AST evaluator. We can fix this by making the parser info an
|
||||||
|
// enum rather than using expressions. It's not clear that evaluation of this is ever really
|
||||||
|
// needed.
|
||||||
|
if let Some(expr) = self.get_parser_info(stack, name) {
|
||||||
|
let expr = expr.clone();
|
||||||
|
let stack = &mut stack.use_call_arg_out_dest();
|
||||||
|
let result = eval_expression::<WithoutDebug>(engine_state, stack, &expr)?;
|
||||||
|
FromValue::from_value(result)
|
||||||
|
} else {
|
||||||
|
Err(ShellError::CantFindColumn {
|
||||||
|
col_name: name.into(),
|
||||||
|
span: None,
|
||||||
|
src_span: self.head,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_positional_args(&self, stack: &Stack, starting_pos: usize) -> bool {
|
fn has_positional_args(&self, stack: &Stack, starting_pos: usize) -> bool {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::ClosureEvalOnce;
|
use crate::ClosureEvalOnce;
|
||||||
use nu_path::canonicalize_with;
|
use nu_path::canonicalize_with;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{Call, Expr},
|
ast::Expr,
|
||||||
engine::{EngineState, Stack, StateWorkingSet},
|
engine::{Call, EngineState, Stack, StateWorkingSet},
|
||||||
Config, ShellError, Span, Value, VarId,
|
Config, ShellError, Span, Value, VarId,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -244,9 +244,9 @@ pub fn path_str(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const DIR_VAR_PARSER_INFO: &str = "dirs_var";
|
pub const DIR_VAR_PARSER_INFO: &str = "dirs_var";
|
||||||
// FIXME: this should be possible on IR calls
|
pub fn get_dirs_var_from_call(stack: &Stack, call: &Call) -> Option<VarId> {
|
||||||
pub fn get_dirs_var_from_call(call: &Call) -> Option<VarId> {
|
call.get_parser_info(stack, DIR_VAR_PARSER_INFO)
|
||||||
call.get_parser_info(DIR_VAR_PARSER_INFO).and_then(|x| {
|
.and_then(|x| {
|
||||||
if let Expr::Var(id) = x.expr {
|
if let Expr::Var(id) = x.expr {
|
||||||
Some(id)
|
Some(id)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -662,7 +662,11 @@ fn eval_call(
|
||||||
.argument_stack
|
.argument_stack
|
||||||
.get_args(*args_base, args_len)
|
.get_args(*args_base, args_len)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.fold(head, |span, arg| span.append(arg.span()));
|
.fold(head, |span, arg| {
|
||||||
|
arg.span()
|
||||||
|
.map(|arg_span| span.append(arg_span))
|
||||||
|
.unwrap_or(span)
|
||||||
|
});
|
||||||
let call = Call {
|
let call = Call {
|
||||||
decl_id,
|
decl_id,
|
||||||
head,
|
head,
|
||||||
|
|
|
@ -189,7 +189,9 @@ fn ir_call_to_extern_call(
|
||||||
extern_call.add_argument(stack, name_arg);
|
extern_call.add_argument(stack, name_arg);
|
||||||
extern_call.add_argument(stack, val_arg);
|
extern_call.add_argument(stack, val_arg);
|
||||||
}
|
}
|
||||||
a @ (engine::Argument::Positional { .. } | engine::Argument::Spread { .. }) => {
|
a @ (engine::Argument::Positional { .. }
|
||||||
|
| engine::Argument::Spread { .. }
|
||||||
|
| engine::Argument::ParserInfo { .. }) => {
|
||||||
let argument = a.clone();
|
let argument = a.clone();
|
||||||
extern_call.add_argument(stack, argument);
|
extern_call.add_argument(stack, argument);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,8 @@ impl MatchPattern {
|
||||||
pub enum Pattern {
|
pub enum Pattern {
|
||||||
Record(Vec<(String, MatchPattern)>),
|
Record(Vec<(String, MatchPattern)>),
|
||||||
List(Vec<MatchPattern>),
|
List(Vec<MatchPattern>),
|
||||||
|
// TODO: it would be nice if this didn't depend on AST
|
||||||
|
// maybe const evaluation can get us to a Value instead?
|
||||||
Value(Expression),
|
Value(Expression),
|
||||||
Variable(VarId),
|
Variable(VarId),
|
||||||
Or(Vec<MatchPattern>),
|
Or(Vec<MatchPattern>),
|
||||||
|
|
|
@ -1,19 +1,14 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{ir::DataSlice, Span, Value};
|
use crate::{ast::Expression, ir::DataSlice, Span, Value};
|
||||||
|
|
||||||
/// Represents a fully evaluated argument to a call.
|
/// Represents a fully evaluated argument to a call.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Argument {
|
pub enum Argument {
|
||||||
/// A positional argument
|
/// A positional argument
|
||||||
Positional {
|
Positional { span: Span, val: Value },
|
||||||
span: Span,
|
/// A spread argument, e.g. `...$args`
|
||||||
val: Value,
|
Spread { span: Span, vals: Value },
|
||||||
},
|
|
||||||
Spread {
|
|
||||||
span: Span,
|
|
||||||
vals: Value,
|
|
||||||
},
|
|
||||||
/// A named argument with no value, e.g. `--flag`
|
/// A named argument with no value, e.g. `--flag`
|
||||||
Flag {
|
Flag {
|
||||||
data: Arc<[u8]>,
|
data: Arc<[u8]>,
|
||||||
|
@ -27,17 +22,27 @@ pub enum Argument {
|
||||||
span: Span,
|
span: Span,
|
||||||
val: Value,
|
val: Value,
|
||||||
},
|
},
|
||||||
|
/// Information generated by the parser for use by certain keyword commands
|
||||||
|
ParserInfo {
|
||||||
|
data: Arc<[u8]>,
|
||||||
|
name: DataSlice,
|
||||||
|
// TODO: rather than `Expression`, this would probably be best served by a specific enum
|
||||||
|
// type for this purpose.
|
||||||
|
expr: Box<Expression>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Argument {
|
impl Argument {
|
||||||
/// The span encompassing the argument's usage within the call, distinct from the span of the
|
/// The span encompassing the argument's usage within the call, distinct from the span of the
|
||||||
/// actual value of the argument.
|
/// actual value of the argument.
|
||||||
pub fn span(&self) -> Span {
|
pub fn span(&self) -> Option<Span> {
|
||||||
match self {
|
match self {
|
||||||
Argument::Positional { span, .. } => *span,
|
Argument::Positional { span, .. } => Some(*span),
|
||||||
Argument::Spread { span, .. } => *span,
|
Argument::Spread { span, .. } => Some(*span),
|
||||||
Argument::Flag { span, .. } => *span,
|
Argument::Flag { span, .. } => Some(*span),
|
||||||
Argument::Named { span, .. } => *span,
|
Argument::Named { span, .. } => Some(*span),
|
||||||
|
// Because `ParserInfo` is generated, its span shouldn't be used
|
||||||
|
Argument::ParserInfo { .. } => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
use crate::{ast, ir, DeclId, FromValue, ShellError, Span, Value};
|
use crate::{
|
||||||
|
ast::{self, Expression},
|
||||||
|
ir, DeclId, FromValue, ShellError, Span, Value,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{EngineState, Stack, StateWorkingSet};
|
use super::{EngineState, Stack, StateWorkingSet};
|
||||||
|
|
||||||
|
@ -117,6 +120,16 @@ impl Call<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a parser info argument by name.
|
||||||
|
pub fn get_parser_info<'a>(&'a self, stack: &'a Stack, name: &str) -> Option<&'a Expression> {
|
||||||
|
match &self.inner {
|
||||||
|
CallImpl::AstRef(call) => call.get_parser_info(name),
|
||||||
|
CallImpl::AstBox(call) => call.get_parser_info(name),
|
||||||
|
CallImpl::IrRef(call) => call.get_parser_info(stack, name),
|
||||||
|
CallImpl::IrBox(call) => call.get_parser_info(stack, name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Evaluator-agnostic implementation of `rest_iter_flattened()`. Evaluates or gets all of the
|
/// Evaluator-agnostic implementation of `rest_iter_flattened()`. Evaluates or gets all of the
|
||||||
/// positional and spread arguments, flattens spreads, and then returns one list of values.
|
/// positional and spread arguments, flattens spreads, and then returns one list of values.
|
||||||
pub fn rest_iter_flattened(
|
pub fn rest_iter_flattened(
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
ast::Expression,
|
||||||
engine::{self, Argument, Stack},
|
engine::{self, Argument, Stack},
|
||||||
DeclId, ShellError, Span, Spanned, Value,
|
DeclId, ShellError, Span, Spanned, Value,
|
||||||
};
|
};
|
||||||
|
@ -55,6 +56,7 @@ impl Call {
|
||||||
Span::new(past.start, self.span.end)
|
Span::new(past.start, self.span.end)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The number of named arguments, with or without values.
|
||||||
pub fn named_len(&self, stack: &Stack) -> usize {
|
pub fn named_len(&self, stack: &Stack) -> usize {
|
||||||
self.arguments(stack)
|
self.arguments(stack)
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -62,6 +64,7 @@ impl Call {
|
||||||
.count()
|
.count()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Iterate through named arguments, with or without values.
|
||||||
pub fn named_iter<'a>(
|
pub fn named_iter<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
stack: &'a Stack,
|
stack: &'a Stack,
|
||||||
|
@ -97,6 +100,8 @@ impl Call {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a named argument's value by name. Returns [`None`] for named arguments with no value as
|
||||||
|
/// well.
|
||||||
pub fn get_named_arg<'a>(&self, stack: &'a Stack, flag_name: &str) -> Option<&'a Value> {
|
pub fn get_named_arg<'a>(&self, stack: &'a Stack, flag_name: &str) -> Option<&'a Value> {
|
||||||
// Optimized to avoid str::from_utf8()
|
// Optimized to avoid str::from_utf8()
|
||||||
self.arguments(stack)
|
self.arguments(stack)
|
||||||
|
@ -115,6 +120,7 @@ impl Call {
|
||||||
.flatten()
|
.flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The number of positional arguments, excluding spread arguments.
|
||||||
pub fn positional_len(&self, stack: &Stack) -> usize {
|
pub fn positional_len(&self, stack: &Stack) -> usize {
|
||||||
self.arguments(stack)
|
self.arguments(stack)
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -122,6 +128,7 @@ impl Call {
|
||||||
.count()
|
.count()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Iterate through positional arguments. Does not include spread arguments.
|
||||||
pub fn positional_iter<'a>(&self, stack: &'a Stack) -> impl Iterator<Item = &'a Value> {
|
pub fn positional_iter<'a>(&self, stack: &'a Stack) -> impl Iterator<Item = &'a Value> {
|
||||||
self.arguments(stack).iter().filter_map(|arg| match arg {
|
self.arguments(stack).iter().filter_map(|arg| match arg {
|
||||||
Argument::Positional { val, .. } => Some(val),
|
Argument::Positional { val, .. } => Some(val),
|
||||||
|
@ -129,6 +136,7 @@ impl Call {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a positional argument by index. Does not include spread arguments.
|
||||||
pub fn positional_nth<'a>(&self, stack: &'a Stack, index: usize) -> Option<&'a Value> {
|
pub fn positional_nth<'a>(&self, stack: &'a Stack, index: usize) -> Option<&'a Value> {
|
||||||
self.positional_iter(stack).nth(index)
|
self.positional_iter(stack).nth(index)
|
||||||
}
|
}
|
||||||
|
@ -150,6 +158,8 @@ impl Call {
|
||||||
.skip(start)
|
.skip(start)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns all of the positional arguments including and after `start`, with spread arguments
|
||||||
|
/// flattened into a single `Vec`.
|
||||||
pub fn rest_iter_flattened(
|
pub fn rest_iter_flattened(
|
||||||
&self,
|
&self,
|
||||||
stack: &Stack,
|
stack: &Stack,
|
||||||
|
@ -174,6 +184,20 @@ impl Call {
|
||||||
Ok(acc)
|
Ok(acc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a parser info argument by name.
|
||||||
|
pub fn get_parser_info<'a>(&self, stack: &'a Stack, name: &str) -> Option<&'a Expression> {
|
||||||
|
self.arguments(stack)
|
||||||
|
.iter()
|
||||||
|
.find_map(|argument| match argument {
|
||||||
|
Argument::ParserInfo {
|
||||||
|
data,
|
||||||
|
name: name_slice,
|
||||||
|
expr,
|
||||||
|
} if &data[*name_slice] == name.as_bytes() => Some(expr.as_ref()),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a span encompassing the entire call.
|
/// Returns a span encompassing the entire call.
|
||||||
pub fn span(&self) -> Span {
|
pub fn span(&self) -> Span {
|
||||||
self.span
|
self.span
|
||||||
|
@ -197,7 +221,9 @@ impl CallBuilder {
|
||||||
self.inner.args_base = stack.argument_stack.get_base();
|
self.inner.args_base = stack.argument_stack.get_base();
|
||||||
}
|
}
|
||||||
self.inner.args_len += 1;
|
self.inner.args_len += 1;
|
||||||
self.inner.span = self.inner.span.append(argument.span());
|
if let Some(span) = argument.span() {
|
||||||
|
self.inner.span = self.inner.span.append(span);
|
||||||
|
}
|
||||||
stack.argument_stack.push(argument);
|
stack.argument_stack.push(argument);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user