Allow parsing modules as scripts (#6357)
* Allow parsing modules as scripts * Remove 'export env' from the supported keywords * Add test for export in blocks; Allow "export use" * Allow evaluating "export alias" * Fmt; Clippy * Allow running "export extern" in scripts
This commit is contained in:
parent
646aace05b
commit
7ef4e5f940
|
@ -274,8 +274,16 @@ pub fn parse_def(
|
||||||
|
|
||||||
// Checking that the function is used with the correct name
|
// Checking that the function is used with the correct name
|
||||||
// Maybe this is not necessary but it is a sanity check
|
// Maybe this is not necessary but it is a sanity check
|
||||||
|
// Note: "export def" is treated the same as "def"
|
||||||
|
|
||||||
let def_call = working_set.get_span_contents(spans[0]).to_vec();
|
let (name_span, split_id) =
|
||||||
|
if spans.len() > 1 && working_set.get_span_contents(spans[0]) == b"export" {
|
||||||
|
(spans[1], 2)
|
||||||
|
} else {
|
||||||
|
(spans[0], 1)
|
||||||
|
};
|
||||||
|
|
||||||
|
let def_call = working_set.get_span_contents(name_span).to_vec();
|
||||||
if def_call != b"def" && def_call != b"def-env" {
|
if def_call != b"def" && def_call != b"def-env" {
|
||||||
return (
|
return (
|
||||||
garbage_pipeline(spans),
|
garbage_pipeline(spans),
|
||||||
|
@ -301,14 +309,15 @@ pub fn parse_def(
|
||||||
}
|
}
|
||||||
Some(decl_id) => {
|
Some(decl_id) => {
|
||||||
working_set.enter_scope();
|
working_set.enter_scope();
|
||||||
|
let (command_spans, rest_spans) = spans.split_at(split_id);
|
||||||
let ParsedInternalCall {
|
let ParsedInternalCall {
|
||||||
call,
|
call,
|
||||||
error: mut err,
|
error: mut err,
|
||||||
output,
|
output,
|
||||||
} = parse_internal_call(
|
} = parse_internal_call(
|
||||||
working_set,
|
working_set,
|
||||||
spans[0],
|
span(command_spans),
|
||||||
&spans[1..],
|
rest_spans,
|
||||||
decl_id,
|
decl_id,
|
||||||
expand_aliases_denylist,
|
expand_aliases_denylist,
|
||||||
);
|
);
|
||||||
|
@ -381,7 +390,7 @@ pub fn parse_def(
|
||||||
error = error.or_else(|| {
|
error = error.or_else(|| {
|
||||||
Some(ParseError::InternalError(
|
Some(ParseError::InternalError(
|
||||||
"Predeclaration failed to add declaration".into(),
|
"Predeclaration failed to add declaration".into(),
|
||||||
spans[1],
|
name_expr.span,
|
||||||
))
|
))
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -415,7 +424,7 @@ pub fn parse_extern(
|
||||||
lite_command: &LiteCommand,
|
lite_command: &LiteCommand,
|
||||||
expand_aliases_denylist: &[usize],
|
expand_aliases_denylist: &[usize],
|
||||||
) -> (Pipeline, Option<ParseError>) {
|
) -> (Pipeline, Option<ParseError>) {
|
||||||
let spans = &lite_command.parts[..];
|
let spans = &lite_command.parts;
|
||||||
let mut error = None;
|
let mut error = None;
|
||||||
|
|
||||||
let usage = build_usage(working_set, &lite_command.comments);
|
let usage = build_usage(working_set, &lite_command.comments);
|
||||||
|
@ -423,7 +432,14 @@ pub fn parse_extern(
|
||||||
// Checking that the function is used with the correct name
|
// Checking that the function is used with the correct name
|
||||||
// Maybe this is not necessary but it is a sanity check
|
// Maybe this is not necessary but it is a sanity check
|
||||||
|
|
||||||
let extern_call = working_set.get_span_contents(spans[0]).to_vec();
|
let (name_span, split_id) =
|
||||||
|
if spans.len() > 1 && working_set.get_span_contents(spans[0]) == b"export" {
|
||||||
|
(spans[1], 2)
|
||||||
|
} else {
|
||||||
|
(spans[0], 1)
|
||||||
|
};
|
||||||
|
|
||||||
|
let extern_call = working_set.get_span_contents(name_span).to_vec();
|
||||||
if extern_call != b"extern" {
|
if extern_call != b"extern" {
|
||||||
return (
|
return (
|
||||||
garbage_pipeline(spans),
|
garbage_pipeline(spans),
|
||||||
|
@ -449,12 +465,15 @@ pub fn parse_extern(
|
||||||
}
|
}
|
||||||
Some(decl_id) => {
|
Some(decl_id) => {
|
||||||
working_set.enter_scope();
|
working_set.enter_scope();
|
||||||
|
|
||||||
|
let (command_spans, rest_spans) = spans.split_at(split_id);
|
||||||
|
|
||||||
let ParsedInternalCall {
|
let ParsedInternalCall {
|
||||||
call, error: err, ..
|
call, error: err, ..
|
||||||
} = parse_internal_call(
|
} = parse_internal_call(
|
||||||
working_set,
|
working_set,
|
||||||
spans[0],
|
span(command_spans),
|
||||||
&spans[1..],
|
rest_spans,
|
||||||
decl_id,
|
decl_id,
|
||||||
expand_aliases_denylist,
|
expand_aliases_denylist,
|
||||||
);
|
);
|
||||||
|
@ -491,7 +510,7 @@ pub fn parse_extern(
|
||||||
error = error.or_else(|| {
|
error = error.or_else(|| {
|
||||||
Some(ParseError::InternalError(
|
Some(ParseError::InternalError(
|
||||||
"Predeclaration failed to add declaration".into(),
|
"Predeclaration failed to add declaration".into(),
|
||||||
spans[1],
|
spans[split_id],
|
||||||
))
|
))
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -525,7 +544,14 @@ pub fn parse_alias(
|
||||||
spans: &[Span],
|
spans: &[Span],
|
||||||
expand_aliases_denylist: &[usize],
|
expand_aliases_denylist: &[usize],
|
||||||
) -> (Pipeline, Option<ParseError>) {
|
) -> (Pipeline, Option<ParseError>) {
|
||||||
let name = working_set.get_span_contents(spans[0]);
|
let (name_span, split_id) =
|
||||||
|
if spans.len() > 1 && working_set.get_span_contents(spans[0]) == b"export" {
|
||||||
|
(spans[1], 2)
|
||||||
|
} else {
|
||||||
|
(spans[0], 1)
|
||||||
|
};
|
||||||
|
|
||||||
|
let name = working_set.get_span_contents(name_span);
|
||||||
|
|
||||||
if name == b"alias" {
|
if name == b"alias" {
|
||||||
if let Some((span, err)) = check_name(working_set, spans) {
|
if let Some((span, err)) = check_name(working_set, spans) {
|
||||||
|
@ -533,10 +559,12 @@ pub fn parse_alias(
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(decl_id) = working_set.find_decl(b"alias", &Type::Any) {
|
if let Some(decl_id) = working_set.find_decl(b"alias", &Type::Any) {
|
||||||
|
let (command_spans, rest_spans) = spans.split_at(split_id);
|
||||||
|
|
||||||
let ParsedInternalCall { call, output, .. } = parse_internal_call(
|
let ParsedInternalCall { call, output, .. } = parse_internal_call(
|
||||||
working_set,
|
working_set,
|
||||||
spans[0],
|
span(command_spans),
|
||||||
&spans[1..],
|
rest_spans,
|
||||||
decl_id,
|
decl_id,
|
||||||
expand_aliases_denylist,
|
expand_aliases_denylist,
|
||||||
);
|
);
|
||||||
|
@ -553,8 +581,8 @@ pub fn parse_alias(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if spans.len() >= 4 {
|
if spans.len() >= split_id + 3 {
|
||||||
let alias_name = working_set.get_span_contents(spans[1]);
|
let alias_name = working_set.get_span_contents(spans[split_id]);
|
||||||
|
|
||||||
let alias_name = if alias_name.starts_with(b"\"")
|
let alias_name = if alias_name.starts_with(b"\"")
|
||||||
&& alias_name.ends_with(b"\"")
|
&& alias_name.ends_with(b"\"")
|
||||||
|
@ -564,9 +592,9 @@ pub fn parse_alias(
|
||||||
} else {
|
} else {
|
||||||
alias_name.to_vec()
|
alias_name.to_vec()
|
||||||
};
|
};
|
||||||
let _equals = working_set.get_span_contents(spans[2]);
|
let _equals = working_set.get_span_contents(spans[split_id + 1]);
|
||||||
|
|
||||||
let replacement = spans[3..].to_vec();
|
let replacement = spans[(split_id + 2)..].to_vec();
|
||||||
|
|
||||||
working_set.add_alias(alias_name, replacement);
|
working_set.add_alias(alias_name, replacement);
|
||||||
}
|
}
|
||||||
|
@ -574,7 +602,7 @@ pub fn parse_alias(
|
||||||
let err = if spans.len() < 4 {
|
let err = if spans.len() < 4 {
|
||||||
Some(ParseError::IncorrectValue(
|
Some(ParseError::IncorrectValue(
|
||||||
"Incomplete alias".into(),
|
"Incomplete alias".into(),
|
||||||
spans[0],
|
span(&spans[..split_id]),
|
||||||
"incomplete alias".into(),
|
"incomplete alias".into(),
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
|
@ -602,7 +630,107 @@ pub fn parse_alias(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_export(
|
// This one will trigger if `export` appears during eval, e.g., in a script
|
||||||
|
pub fn parse_export_in_block(
|
||||||
|
working_set: &mut StateWorkingSet,
|
||||||
|
lite_command: &LiteCommand,
|
||||||
|
expand_aliases_denylist: &[usize],
|
||||||
|
) -> (Pipeline, Option<ParseError>) {
|
||||||
|
let call_span = span(&lite_command.parts);
|
||||||
|
|
||||||
|
let full_name = if lite_command.parts.len() > 1 {
|
||||||
|
let sub = working_set.get_span_contents(lite_command.parts[1]);
|
||||||
|
match sub {
|
||||||
|
b"alias" | b"def" | b"def-env" | b"extern" | b"use" => [b"export ", sub].concat(),
|
||||||
|
_ => b"export".to_vec(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
b"export".to_vec()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(decl_id) = working_set.find_decl(&full_name, &Type::Any) {
|
||||||
|
let ParsedInternalCall {
|
||||||
|
call,
|
||||||
|
error: mut err,
|
||||||
|
output,
|
||||||
|
..
|
||||||
|
} = parse_internal_call(
|
||||||
|
working_set,
|
||||||
|
if full_name == b"export" {
|
||||||
|
lite_command.parts[0]
|
||||||
|
} else {
|
||||||
|
span(&lite_command.parts[0..2])
|
||||||
|
},
|
||||||
|
if full_name == b"export" {
|
||||||
|
&lite_command.parts[1..]
|
||||||
|
} else {
|
||||||
|
&lite_command.parts[2..]
|
||||||
|
},
|
||||||
|
decl_id,
|
||||||
|
expand_aliases_denylist,
|
||||||
|
);
|
||||||
|
|
||||||
|
let decl = working_set.get_decl(decl_id);
|
||||||
|
err = check_call(call_span, &decl.signature(), &call).or(err);
|
||||||
|
|
||||||
|
if err.is_some() || call.has_flag("help") {
|
||||||
|
return (
|
||||||
|
Pipeline::from_vec(vec![Expression {
|
||||||
|
expr: Expr::Call(call),
|
||||||
|
span: call_span,
|
||||||
|
ty: output,
|
||||||
|
custom_completion: None,
|
||||||
|
}]),
|
||||||
|
err,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
garbage_pipeline(&lite_command.parts),
|
||||||
|
Some(ParseError::UnknownState(
|
||||||
|
format!(
|
||||||
|
"internal error: '{}' declaration not found",
|
||||||
|
String::from_utf8_lossy(&full_name)
|
||||||
|
),
|
||||||
|
span(&lite_command.parts),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
if &full_name == b"export" {
|
||||||
|
// export by itself is meaningless
|
||||||
|
return (
|
||||||
|
garbage_pipeline(&lite_command.parts),
|
||||||
|
Some(ParseError::UnexpectedKeyword(
|
||||||
|
"export".into(),
|
||||||
|
lite_command.parts[0],
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
match full_name.as_slice() {
|
||||||
|
b"export alias" => parse_alias(working_set, &lite_command.parts, expand_aliases_denylist),
|
||||||
|
b"export def" | b"export def-env" => {
|
||||||
|
parse_def(working_set, lite_command, expand_aliases_denylist)
|
||||||
|
}
|
||||||
|
b"export use" => {
|
||||||
|
let (pipeline, _, err) =
|
||||||
|
parse_use(working_set, &lite_command.parts, expand_aliases_denylist);
|
||||||
|
(pipeline, err)
|
||||||
|
}
|
||||||
|
b"export extern" => parse_extern(working_set, lite_command, expand_aliases_denylist),
|
||||||
|
_ => (
|
||||||
|
garbage_pipeline(&lite_command.parts),
|
||||||
|
Some(ParseError::UnexpectedKeyword(
|
||||||
|
String::from_utf8_lossy(&full_name).to_string(),
|
||||||
|
lite_command.parts[0],
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This one will trigger only in a module
|
||||||
|
pub fn parse_export_in_module(
|
||||||
working_set: &mut StateWorkingSet,
|
working_set: &mut StateWorkingSet,
|
||||||
lite_command: &LiteCommand,
|
lite_command: &LiteCommand,
|
||||||
expand_aliases_denylist: &[usize],
|
expand_aliases_denylist: &[usize],
|
||||||
|
@ -1163,7 +1291,7 @@ pub fn parse_module_block(
|
||||||
// will work only if you call `use foo *; b` but not with `use foo; foo b`
|
// will work only if you call `use foo *; b` but not with `use foo; foo b`
|
||||||
// since in the second case, the name of the env var would be $env."foo a".
|
// since in the second case, the name of the env var would be $env."foo a".
|
||||||
b"export" => {
|
b"export" => {
|
||||||
let (pipe, exportables, err) = parse_export(
|
let (pipe, exportables, err) = parse_export_in_module(
|
||||||
working_set,
|
working_set,
|
||||||
&pipeline.commands[0],
|
&pipeline.commands[0],
|
||||||
expand_aliases_denylist,
|
expand_aliases_denylist,
|
||||||
|
@ -1309,7 +1437,26 @@ pub fn parse_use(
|
||||||
spans: &[Span],
|
spans: &[Span],
|
||||||
expand_aliases_denylist: &[usize],
|
expand_aliases_denylist: &[usize],
|
||||||
) -> (Pipeline, Vec<Exportable>, Option<ParseError>) {
|
) -> (Pipeline, Vec<Exportable>, Option<ParseError>) {
|
||||||
if working_set.get_span_contents(spans[0]) != b"use" {
|
let (name_span, split_id) =
|
||||||
|
if spans.len() > 1 && working_set.get_span_contents(spans[0]) == b"export" {
|
||||||
|
(spans[1], 2)
|
||||||
|
} else {
|
||||||
|
(spans[0], 1)
|
||||||
|
};
|
||||||
|
|
||||||
|
let use_call = working_set.get_span_contents(name_span).to_vec();
|
||||||
|
if use_call != b"use" {
|
||||||
|
return (
|
||||||
|
garbage_pipeline(spans),
|
||||||
|
vec![],
|
||||||
|
Some(ParseError::UnknownState(
|
||||||
|
"internal error: Wrong call name for 'use' command".into(),
|
||||||
|
span(spans),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if working_set.get_span_contents(name_span) != b"use" {
|
||||||
return (
|
return (
|
||||||
garbage_pipeline(spans),
|
garbage_pipeline(spans),
|
||||||
vec![],
|
vec![],
|
||||||
|
@ -1322,14 +1469,16 @@ pub fn parse_use(
|
||||||
|
|
||||||
let (call, call_span, use_decl_id) = match working_set.find_decl(b"use", &Type::Any) {
|
let (call, call_span, use_decl_id) = match working_set.find_decl(b"use", &Type::Any) {
|
||||||
Some(decl_id) => {
|
Some(decl_id) => {
|
||||||
|
let (command_spans, rest_spans) = spans.split_at(split_id);
|
||||||
|
|
||||||
let ParsedInternalCall {
|
let ParsedInternalCall {
|
||||||
call,
|
call,
|
||||||
error: mut err,
|
error: mut err,
|
||||||
output,
|
output,
|
||||||
} = parse_internal_call(
|
} = parse_internal_call(
|
||||||
working_set,
|
working_set,
|
||||||
spans[0],
|
span(command_spans),
|
||||||
&spans[1..],
|
rest_spans,
|
||||||
decl_id,
|
decl_id,
|
||||||
expand_aliases_denylist,
|
expand_aliases_denylist,
|
||||||
);
|
);
|
||||||
|
@ -1420,7 +1569,7 @@ pub fn parse_use(
|
||||||
custom_completion: None,
|
custom_completion: None,
|
||||||
}]),
|
}]),
|
||||||
vec![],
|
vec![],
|
||||||
Some(ParseError::ModuleNotFound(spans[1])),
|
Some(ParseError::ModuleNotFound(import_pattern.head.span)),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1458,7 +1607,7 @@ pub fn parse_use(
|
||||||
head: ImportPatternHead {
|
head: ImportPatternHead {
|
||||||
name: module_name.into(),
|
name: module_name.into(),
|
||||||
id: Some(module_id),
|
id: Some(module_id),
|
||||||
span: spans[1],
|
span: import_pattern.head.span,
|
||||||
},
|
},
|
||||||
members: import_pattern.members,
|
members: import_pattern.members,
|
||||||
hidden: HashSet::new(),
|
hidden: HashSet::new(),
|
||||||
|
@ -1474,14 +1623,16 @@ pub fn parse_use(
|
||||||
custom_completion: None,
|
custom_completion: None,
|
||||||
}]),
|
}]),
|
||||||
vec![],
|
vec![],
|
||||||
Some(ParseError::ModuleNotFound(spans[1])),
|
Some(ParseError::ModuleNotFound(import_pattern.head.span)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error = error.or(Some(ParseError::ModuleNotFound(import_pattern.head.span)));
|
error = error.or(Some(ParseError::ModuleNotFound(import_pattern.head.span)));
|
||||||
|
|
||||||
|
let old_span = import_pattern.head.span;
|
||||||
|
|
||||||
let mut import_pattern = ImportPattern::new();
|
let mut import_pattern = ImportPattern::new();
|
||||||
import_pattern.head.span = spans[1];
|
import_pattern.head.span = old_span;
|
||||||
|
|
||||||
(import_pattern, Module::new())
|
(import_pattern, Module::new())
|
||||||
}
|
}
|
||||||
|
@ -1489,7 +1640,7 @@ pub fn parse_use(
|
||||||
return (
|
return (
|
||||||
garbage_pipeline(spans),
|
garbage_pipeline(spans),
|
||||||
vec![],
|
vec![],
|
||||||
Some(ParseError::NonUtf8(spans[1])),
|
Some(ParseError::NonUtf8(import_pattern.head.span)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1565,7 +1716,7 @@ pub fn parse_use(
|
||||||
};
|
};
|
||||||
|
|
||||||
let call = Box::new(Call {
|
let call = Box::new(Call {
|
||||||
head: spans[0],
|
head: span(spans.split_at(split_id).0),
|
||||||
decl_id: use_decl_id,
|
decl_id: use_decl_id,
|
||||||
arguments: vec![Argument::Positional(import_pattern_expr)],
|
arguments: vec![Argument::Positional(import_pattern_expr)],
|
||||||
redirect_stdout: true,
|
redirect_stdout: true,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
lex, lite_parse,
|
lex, lite_parse,
|
||||||
lite_parse::LiteCommand,
|
lite_parse::LiteCommand,
|
||||||
|
parse_export_in_block,
|
||||||
parse_keywords::{parse_extern, parse_for, parse_source},
|
parse_keywords::{parse_extern, parse_for, parse_source},
|
||||||
type_check::{math_result_type, type_compatible},
|
type_check::{math_result_type, type_compatible},
|
||||||
LiteBlock, ParseError, Token, TokenContents,
|
LiteBlock, ParseError, Token, TokenContents,
|
||||||
|
@ -231,30 +232,42 @@ pub fn check_name<'a>(
|
||||||
working_set: &mut StateWorkingSet,
|
working_set: &mut StateWorkingSet,
|
||||||
spans: &'a [Span],
|
spans: &'a [Span],
|
||||||
) -> Option<(&'a Span, ParseError)> {
|
) -> Option<(&'a Span, ParseError)> {
|
||||||
|
let command_len = if !spans.is_empty() {
|
||||||
|
if working_set.get_span_contents(spans[0]) == b"export" {
|
||||||
|
2
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
if spans.len() == 1 {
|
if spans.len() == 1 {
|
||||||
None
|
None
|
||||||
} else if spans.len() < 4 {
|
} else if spans.len() < command_len + 3 {
|
||||||
if working_set.get_span_contents(spans[1]) == b"=" {
|
if working_set.get_span_contents(spans[command_len]) == b"=" {
|
||||||
let name = String::from_utf8_lossy(working_set.get_span_contents(spans[0]));
|
let name =
|
||||||
|
String::from_utf8_lossy(working_set.get_span_contents(span(&spans[..command_len])));
|
||||||
Some((
|
Some((
|
||||||
&spans[1],
|
&spans[command_len],
|
||||||
ParseError::AssignmentMismatch(
|
ParseError::AssignmentMismatch(
|
||||||
format!("{} missing name", name),
|
format!("{} missing name", name),
|
||||||
"missing name".into(),
|
"missing name".into(),
|
||||||
spans[1],
|
spans[command_len],
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
} else if working_set.get_span_contents(spans[2]) != b"=" {
|
} else if working_set.get_span_contents(spans[command_len + 1]) != b"=" {
|
||||||
let name = String::from_utf8_lossy(working_set.get_span_contents(spans[0]));
|
let name =
|
||||||
|
String::from_utf8_lossy(working_set.get_span_contents(span(&spans[..command_len])));
|
||||||
Some((
|
Some((
|
||||||
&spans[2],
|
&spans[command_len + 1],
|
||||||
ParseError::AssignmentMismatch(
|
ParseError::AssignmentMismatch(
|
||||||
format!("{} missing sign", name),
|
format!("{} missing sign", name),
|
||||||
"missing equal sign".into(),
|
"missing equal sign".into(),
|
||||||
spans[2],
|
spans[command_len + 1],
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
|
@ -4793,64 +4806,7 @@ pub fn parse_builtin_commands(
|
||||||
}
|
}
|
||||||
b"overlay" => parse_overlay(working_set, &lite_command.parts, expand_aliases_denylist),
|
b"overlay" => parse_overlay(working_set, &lite_command.parts, expand_aliases_denylist),
|
||||||
b"source" => parse_source(working_set, &lite_command.parts, expand_aliases_denylist),
|
b"source" => parse_source(working_set, &lite_command.parts, expand_aliases_denylist),
|
||||||
b"export" => {
|
b"export" => parse_export_in_block(working_set, lite_command, expand_aliases_denylist),
|
||||||
let full_decl = if lite_command.parts.len() > 1 {
|
|
||||||
let sub = working_set.get_span_contents(lite_command.parts[1]);
|
|
||||||
match sub {
|
|
||||||
b"alias" | b"def" | b"def-env" | b"env" | b"extern" | b"use" => {
|
|
||||||
[b"export ", sub].concat()
|
|
||||||
}
|
|
||||||
_ => b"export".to_vec(),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
b"export".to_vec()
|
|
||||||
};
|
|
||||||
if let Some(decl_id) = working_set.find_decl(&full_decl, &Type::Any) {
|
|
||||||
let parsed_call = parse_internal_call(
|
|
||||||
working_set,
|
|
||||||
if full_decl == b"export" {
|
|
||||||
lite_command.parts[0]
|
|
||||||
} else {
|
|
||||||
span(&lite_command.parts[0..2])
|
|
||||||
},
|
|
||||||
if full_decl == b"export" {
|
|
||||||
&lite_command.parts[1..]
|
|
||||||
} else {
|
|
||||||
&lite_command.parts[2..]
|
|
||||||
},
|
|
||||||
decl_id,
|
|
||||||
expand_aliases_denylist,
|
|
||||||
);
|
|
||||||
|
|
||||||
if parsed_call.call.has_flag("help") {
|
|
||||||
(
|
|
||||||
Pipeline::from_vec(vec![Expression {
|
|
||||||
expr: Expr::Call(parsed_call.call),
|
|
||||||
span: span(&lite_command.parts),
|
|
||||||
ty: parsed_call.output,
|
|
||||||
custom_completion: None,
|
|
||||||
}]),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
(
|
|
||||||
garbage_pipeline(&lite_command.parts),
|
|
||||||
Some(ParseError::UnexpectedKeyword(
|
|
||||||
"export".into(),
|
|
||||||
lite_command.parts[0],
|
|
||||||
)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
(
|
|
||||||
garbage_pipeline(&lite_command.parts),
|
|
||||||
Some(ParseError::UnexpectedKeyword(
|
|
||||||
"export".into(),
|
|
||||||
lite_command.parts[0],
|
|
||||||
)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b"hide" => parse_hide(working_set, &lite_command.parts, expand_aliases_denylist),
|
b"hide" => parse_hide(working_set, &lite_command.parts, expand_aliases_denylist),
|
||||||
#[cfg(feature = "plugin")]
|
#[cfg(feature = "plugin")]
|
||||||
b"register" => parse_register(working_set, &lite_command.parts, expand_aliases_denylist),
|
b"register" => parse_register(working_set, &lite_command.parts, expand_aliases_denylist),
|
||||||
|
|
|
@ -170,3 +170,32 @@ fn nu_lib_dirs_relative_script() {
|
||||||
assert_eq!(actual_repl.out, "foo");
|
assert_eq!(actual_repl.out, "foo");
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn run_script_that_looks_like_module() {
|
||||||
|
Playground::setup("run_script_that_looks_like_module", |dirs, _| {
|
||||||
|
let inp_lines = &[
|
||||||
|
r#"module spam { export def eggs [] { 'eggs' } }"#,
|
||||||
|
r#"export use spam eggs"#,
|
||||||
|
r#"export def foo [] { eggs }"#,
|
||||||
|
r#"export alias bar = foo"#,
|
||||||
|
r#"export def-env baz [] { bar }"#,
|
||||||
|
r#"baz"#,
|
||||||
|
];
|
||||||
|
|
||||||
|
let actual = nu!(cwd: dirs.test(), inp_lines.join("; "));
|
||||||
|
|
||||||
|
assert_eq!(actual.out, "eggs");
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn run_export_extern() {
|
||||||
|
Playground::setup("run_script_that_looks_like_module", |dirs, _| {
|
||||||
|
let inp_lines = &[r#"export extern foo []"#, r#"help foo"#];
|
||||||
|
|
||||||
|
let actual = nu!(cwd: dirs.test(), inp_lines.join("; "));
|
||||||
|
|
||||||
|
assert!(actual.out.contains("Usage"));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user