mirror of
https://github.com/nushell/nushell.git
synced 2024-11-26 02:13:47 +01:00
input and output types (#5750)
* input and output types * added description * type from stored variable * string in custom value * more tests with non custom
This commit is contained in:
parent
9d10007085
commit
d5b99ae316
@ -4,6 +4,7 @@ use log::trace;
|
|||||||
use miette::{IntoDiagnostic, Result};
|
use miette::{IntoDiagnostic, Result};
|
||||||
use nu_engine::convert_env_values;
|
use nu_engine::convert_env_values;
|
||||||
use nu_parser::parse;
|
use nu_parser::parse;
|
||||||
|
use nu_protocol::Type;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::Call,
|
ast::Call,
|
||||||
engine::{EngineState, Stack, StateWorkingSet},
|
engine::{EngineState, Stack, StateWorkingSet},
|
||||||
@ -34,7 +35,7 @@ pub fn evaluate_file(
|
|||||||
|
|
||||||
let _ = parse(&mut working_set, Some(&path), &file, false, &[]);
|
let _ = parse(&mut working_set, Some(&path), &file, false, &[]);
|
||||||
|
|
||||||
if working_set.find_decl(b"main").is_some() {
|
if working_set.find_decl(b"main", &Type::Any).is_some() {
|
||||||
let args = format!("main {}", args.join(" "));
|
let args = format!("main {}", args.join(" "));
|
||||||
|
|
||||||
if !eval_source(
|
if !eval_source(
|
||||||
|
@ -91,7 +91,7 @@ impl CustomValue for ExprDb {
|
|||||||
Value::Bool { val, .. } => Ok(Expr::Value(sqlparser::ast::Value::Boolean(*val))),
|
Value::Bool { val, .. } => Ok(Expr::Value(sqlparser::ast::Value::Boolean(*val))),
|
||||||
_ => Err(ShellError::OperatorMismatch {
|
_ => Err(ShellError::OperatorMismatch {
|
||||||
op_span: op,
|
op_span: op,
|
||||||
lhs_ty: Type::Custom,
|
lhs_ty: Type::Custom(self.typetag_name().into()),
|
||||||
lhs_span,
|
lhs_span,
|
||||||
rhs_ty: right.get_type(),
|
rhs_ty: right.get_type(),
|
||||||
rhs_span: right.span()?,
|
rhs_span: right.span()?,
|
||||||
|
@ -126,9 +126,9 @@ fn with_operator(
|
|||||||
.into_value(lhs_span)),
|
.into_value(lhs_span)),
|
||||||
_ => Err(ShellError::OperatorMismatch {
|
_ => Err(ShellError::OperatorMismatch {
|
||||||
op_span,
|
op_span,
|
||||||
lhs_ty: Type::Custom,
|
lhs_ty: Type::Custom(left.typetag_name().into()),
|
||||||
lhs_span,
|
lhs_span,
|
||||||
rhs_ty: Type::Custom,
|
rhs_ty: Type::Custom(right.typetag_name().into()),
|
||||||
rhs_span,
|
rhs_span,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
@ -829,7 +829,7 @@ pub fn create_scope(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
for (command_name, decl_id) in commands_map {
|
for ((command_name, _), decl_id) in commands_map {
|
||||||
if visibility.is_decl_id_visible(decl_id) {
|
if visibility.is_decl_id_visible(decl_id) {
|
||||||
let mut cols = vec![];
|
let mut cols = vec![];
|
||||||
let mut vals = vec![];
|
let mut vals = vec![];
|
||||||
|
@ -115,7 +115,7 @@ pub fn parse_for(
|
|||||||
// Parsing the spans and checking that they match the register signature
|
// Parsing the spans and checking that they match the register signature
|
||||||
// Using a parsed call makes more sense than checking for how many spans are in the call
|
// Using a parsed call makes more sense than checking for how many spans are in the call
|
||||||
// Also, by creating a call, it can be checked if it matches the declaration signature
|
// Also, by creating a call, it can be checked if it matches the declaration signature
|
||||||
let (call, call_span) = match working_set.find_decl(b"for") {
|
let (call, call_span) = match working_set.find_decl(b"for", &Type::Any) {
|
||||||
None => {
|
None => {
|
||||||
return (
|
return (
|
||||||
garbage(spans[0]),
|
garbage(spans[0]),
|
||||||
@ -284,7 +284,7 @@ pub fn parse_def(
|
|||||||
// Parsing the spans and checking that they match the register signature
|
// Parsing the spans and checking that they match the register signature
|
||||||
// Using a parsed call makes more sense than checking for how many spans are in the call
|
// Using a parsed call makes more sense than checking for how many spans are in the call
|
||||||
// Also, by creating a call, it can be checked if it matches the declaration signature
|
// Also, by creating a call, it can be checked if it matches the declaration signature
|
||||||
let (call, call_span) = match working_set.find_decl(&def_call) {
|
let (call, call_span) = match working_set.find_decl(&def_call, &Type::Any) {
|
||||||
None => {
|
None => {
|
||||||
return (
|
return (
|
||||||
garbage_pipeline(spans),
|
garbage_pipeline(spans),
|
||||||
@ -427,7 +427,7 @@ pub fn parse_extern(
|
|||||||
// Parsing the spans and checking that they match the register signature
|
// Parsing the spans and checking that they match the register signature
|
||||||
// Using a parsed call makes more sense than checking for how many spans are in the call
|
// Using a parsed call makes more sense than checking for how many spans are in the call
|
||||||
// Also, by creating a call, it can be checked if it matches the declaration signature
|
// Also, by creating a call, it can be checked if it matches the declaration signature
|
||||||
let (call, call_span) = match working_set.find_decl(&extern_call) {
|
let (call, call_span) = match working_set.find_decl(&extern_call, &Type::Any) {
|
||||||
None => {
|
None => {
|
||||||
return (
|
return (
|
||||||
garbage_pipeline(spans),
|
garbage_pipeline(spans),
|
||||||
@ -520,7 +520,7 @@ pub fn parse_alias(
|
|||||||
return (Pipeline::from_vec(vec![garbage(*span)]), Some(err));
|
return (Pipeline::from_vec(vec![garbage(*span)]), Some(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(decl_id) = working_set.find_decl(b"alias") {
|
if let Some(decl_id) = working_set.find_decl(b"alias", &Type::Any) {
|
||||||
let (call, _) = parse_internal_call(
|
let (call, _) = parse_internal_call(
|
||||||
working_set,
|
working_set,
|
||||||
spans[0],
|
spans[0],
|
||||||
@ -622,7 +622,7 @@ pub fn parse_export(
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
let export_decl_id = if let Some(id) = working_set.find_decl(b"export") {
|
let export_decl_id = if let Some(id) = working_set.find_decl(b"export", &Type::Any) {
|
||||||
id
|
id
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
@ -655,18 +655,19 @@ pub fn parse_export(
|
|||||||
parse_def(working_set, &lite_command, expand_aliases_denylist);
|
parse_def(working_set, &lite_command, expand_aliases_denylist);
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
|
|
||||||
let export_def_decl_id = if let Some(id) = working_set.find_decl(b"export def") {
|
let export_def_decl_id =
|
||||||
id
|
if let Some(id) = working_set.find_decl(b"export def", &Type::Any) {
|
||||||
} else {
|
id
|
||||||
return (
|
} else {
|
||||||
garbage_pipeline(spans),
|
return (
|
||||||
None,
|
garbage_pipeline(spans),
|
||||||
Some(ParseError::InternalError(
|
None,
|
||||||
"missing 'export def' command".into(),
|
Some(ParseError::InternalError(
|
||||||
export_span,
|
"missing 'export def' command".into(),
|
||||||
)),
|
export_span,
|
||||||
);
|
)),
|
||||||
};
|
);
|
||||||
|
};
|
||||||
|
|
||||||
// Trying to warp the 'def' call into the 'export def' in a very clumsy way
|
// Trying to warp the 'def' call into the 'export def' in a very clumsy way
|
||||||
if let Some(Expression {
|
if let Some(Expression {
|
||||||
@ -690,7 +691,7 @@ pub fn parse_export(
|
|||||||
if error.is_none() {
|
if error.is_none() {
|
||||||
let decl_name = working_set.get_span_contents(spans[2]);
|
let decl_name = working_set.get_span_contents(spans[2]);
|
||||||
let decl_name = trim_quotes(decl_name);
|
let decl_name = trim_quotes(decl_name);
|
||||||
if let Some(decl_id) = working_set.find_decl(decl_name) {
|
if let Some(decl_id) = working_set.find_decl(decl_name, &Type::Any) {
|
||||||
Some(Exportable::Decl(decl_id))
|
Some(Exportable::Decl(decl_id))
|
||||||
} else {
|
} else {
|
||||||
error = error.or_else(|| {
|
error = error.or_else(|| {
|
||||||
@ -714,19 +715,19 @@ pub fn parse_export(
|
|||||||
parse_def(working_set, &lite_command, expand_aliases_denylist);
|
parse_def(working_set, &lite_command, expand_aliases_denylist);
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
|
|
||||||
let export_def_decl_id = if let Some(id) = working_set.find_decl(b"export def-env")
|
let export_def_decl_id =
|
||||||
{
|
if let Some(id) = working_set.find_decl(b"export def-env", &Type::Any) {
|
||||||
id
|
id
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
garbage_pipeline(spans),
|
garbage_pipeline(spans),
|
||||||
None,
|
None,
|
||||||
Some(ParseError::InternalError(
|
Some(ParseError::InternalError(
|
||||||
"missing 'export def-env' command".into(),
|
"missing 'export def-env' command".into(),
|
||||||
export_span,
|
export_span,
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Trying to warp the 'def' call into the 'export def' in a very clumsy way
|
// Trying to warp the 'def' call into the 'export def' in a very clumsy way
|
||||||
if let Some(Expression {
|
if let Some(Expression {
|
||||||
@ -750,7 +751,7 @@ pub fn parse_export(
|
|||||||
if error.is_none() {
|
if error.is_none() {
|
||||||
let decl_name = working_set.get_span_contents(spans[2]);
|
let decl_name = working_set.get_span_contents(spans[2]);
|
||||||
let decl_name = trim_quotes(decl_name);
|
let decl_name = trim_quotes(decl_name);
|
||||||
if let Some(decl_id) = working_set.find_decl(decl_name) {
|
if let Some(decl_id) = working_set.find_decl(decl_name, &Type::Any) {
|
||||||
Some(Exportable::Decl(decl_id))
|
Some(Exportable::Decl(decl_id))
|
||||||
} else {
|
} else {
|
||||||
error = error.or_else(|| {
|
error = error.or_else(|| {
|
||||||
@ -774,18 +775,19 @@ pub fn parse_export(
|
|||||||
parse_extern(working_set, &lite_command, expand_aliases_denylist);
|
parse_extern(working_set, &lite_command, expand_aliases_denylist);
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
|
|
||||||
let export_def_decl_id = if let Some(id) = working_set.find_decl(b"export extern") {
|
let export_def_decl_id =
|
||||||
id
|
if let Some(id) = working_set.find_decl(b"export extern", &Type::Any) {
|
||||||
} else {
|
id
|
||||||
return (
|
} else {
|
||||||
garbage_pipeline(spans),
|
return (
|
||||||
None,
|
garbage_pipeline(spans),
|
||||||
Some(ParseError::InternalError(
|
None,
|
||||||
"missing 'export extern' command".into(),
|
Some(ParseError::InternalError(
|
||||||
export_span,
|
"missing 'export extern' command".into(),
|
||||||
)),
|
export_span,
|
||||||
);
|
)),
|
||||||
};
|
);
|
||||||
|
};
|
||||||
|
|
||||||
// Trying to warp the 'def' call into the 'export def' in a very clumsy way
|
// Trying to warp the 'def' call into the 'export def' in a very clumsy way
|
||||||
if let Some(Expression {
|
if let Some(Expression {
|
||||||
@ -809,7 +811,7 @@ pub fn parse_export(
|
|||||||
if error.is_none() {
|
if error.is_none() {
|
||||||
let decl_name = working_set.get_span_contents(spans[2]);
|
let decl_name = working_set.get_span_contents(spans[2]);
|
||||||
let decl_name = trim_quotes(decl_name);
|
let decl_name = trim_quotes(decl_name);
|
||||||
if let Some(decl_id) = working_set.find_decl(decl_name) {
|
if let Some(decl_id) = working_set.find_decl(decl_name, &Type::Any) {
|
||||||
Some(Exportable::Decl(decl_id))
|
Some(Exportable::Decl(decl_id))
|
||||||
} else {
|
} else {
|
||||||
error = error.or_else(|| {
|
error = error.or_else(|| {
|
||||||
@ -833,19 +835,19 @@ pub fn parse_export(
|
|||||||
parse_alias(working_set, &lite_command.parts, expand_aliases_denylist);
|
parse_alias(working_set, &lite_command.parts, expand_aliases_denylist);
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
|
|
||||||
let export_alias_decl_id = if let Some(id) = working_set.find_decl(b"export alias")
|
let export_alias_decl_id =
|
||||||
{
|
if let Some(id) = working_set.find_decl(b"export alias", &Type::Any) {
|
||||||
id
|
id
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
garbage_pipeline(spans),
|
garbage_pipeline(spans),
|
||||||
None,
|
None,
|
||||||
Some(ParseError::InternalError(
|
Some(ParseError::InternalError(
|
||||||
"missing 'export alias' command".into(),
|
"missing 'export alias' command".into(),
|
||||||
export_span,
|
export_span,
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Trying to warp the 'alias' call into the 'export alias' in a very clumsy way
|
// Trying to warp the 'alias' call into the 'export alias' in a very clumsy way
|
||||||
if let Some(Expression {
|
if let Some(Expression {
|
||||||
@ -885,7 +887,7 @@ pub fn parse_export(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
b"env" => {
|
b"env" => {
|
||||||
if let Some(id) = working_set.find_decl(b"export env") {
|
if let Some(id) = working_set.find_decl(b"export env", &Type::Any) {
|
||||||
call.decl_id = id;
|
call.decl_id = id;
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
@ -1190,7 +1192,7 @@ pub fn parse_module(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let module_decl_id = working_set
|
let module_decl_id = working_set
|
||||||
.find_decl(b"module")
|
.find_decl(b"module", &Type::Any)
|
||||||
.expect("internal error: missing module command");
|
.expect("internal error: missing module command");
|
||||||
|
|
||||||
let call = Box::new(Call {
|
let call = Box::new(Call {
|
||||||
@ -1239,7 +1241,7 @@ pub fn parse_use(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (call, call_span, use_decl_id) = match working_set.find_decl(b"use") {
|
let (call, call_span, use_decl_id) = match working_set.find_decl(b"use", &Type::Any) {
|
||||||
Some(decl_id) => {
|
Some(decl_id) => {
|
||||||
let (call, mut err) = parse_internal_call(
|
let (call, mut err) = parse_internal_call(
|
||||||
working_set,
|
working_set,
|
||||||
@ -1472,7 +1474,7 @@ pub fn parse_hide(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (call, call_span, hide_decl_id) = match working_set.find_decl(b"hide") {
|
let (call, call_span, hide_decl_id) = match working_set.find_decl(b"hide", &Type::Any) {
|
||||||
Some(decl_id) => {
|
Some(decl_id) => {
|
||||||
let (call, mut err) = parse_internal_call(
|
let (call, mut err) = parse_internal_call(
|
||||||
working_set,
|
working_set,
|
||||||
@ -1542,33 +1544,34 @@ pub fn parse_hide(
|
|||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (is_module, module) =
|
let (is_module, module) = if let Some(module_id) =
|
||||||
if let Some(module_id) = working_set.find_module(&import_pattern.head.name) {
|
working_set.find_module(&import_pattern.head.name)
|
||||||
(true, working_set.get_module(module_id).clone())
|
{
|
||||||
} else if import_pattern.members.is_empty() {
|
(true, working_set.get_module(module_id).clone())
|
||||||
// The pattern head can be:
|
} else if import_pattern.members.is_empty() {
|
||||||
if let Some(id) = working_set.find_alias(&import_pattern.head.name) {
|
// The pattern head can be:
|
||||||
// an alias,
|
if let Some(id) = working_set.find_alias(&import_pattern.head.name) {
|
||||||
let mut module = Module::new();
|
// an alias,
|
||||||
module.add_alias(&import_pattern.head.name, id);
|
let mut module = Module::new();
|
||||||
|
module.add_alias(&import_pattern.head.name, id);
|
||||||
|
|
||||||
(false, module)
|
(false, module)
|
||||||
} else if let Some(id) = working_set.find_decl(&import_pattern.head.name) {
|
} else if let Some(id) = working_set.find_decl(&import_pattern.head.name, &Type::Any) {
|
||||||
// a custom command,
|
// a custom command,
|
||||||
let mut module = Module::new();
|
let mut module = Module::new();
|
||||||
module.add_decl(&import_pattern.head.name, id);
|
module.add_decl(&import_pattern.head.name, id);
|
||||||
|
|
||||||
(false, module)
|
(false, module)
|
||||||
} else {
|
|
||||||
// , or it could be an env var (handled by the engine)
|
|
||||||
(false, Module::new())
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return (
|
// , or it could be an env var (handled by the engine)
|
||||||
garbage_pipeline(spans),
|
(false, Module::new())
|
||||||
Some(ParseError::ModuleNotFound(spans[1])),
|
}
|
||||||
);
|
} else {
|
||||||
};
|
return (
|
||||||
|
garbage_pipeline(spans),
|
||||||
|
Some(ParseError::ModuleNotFound(spans[1])),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
// This kind of inverts the import pattern matching found in parse_use()
|
// This kind of inverts the import pattern matching found in parse_use()
|
||||||
let (aliases_to_hide, decls_to_hide) = if import_pattern.members.is_empty() {
|
let (aliases_to_hide, decls_to_hide) = if import_pattern.members.is_empty() {
|
||||||
@ -1696,7 +1699,7 @@ pub fn parse_overlay(
|
|||||||
}
|
}
|
||||||
b"list" => {
|
b"list" => {
|
||||||
// TODO: Abstract this code blob, it's repeated all over the place:
|
// TODO: Abstract this code blob, it's repeated all over the place:
|
||||||
let call = match working_set.find_decl(b"overlay list") {
|
let call = match working_set.find_decl(b"overlay list", &Type::Any) {
|
||||||
Some(decl_id) => {
|
Some(decl_id) => {
|
||||||
let (call, mut err) = parse_internal_call(
|
let (call, mut err) = parse_internal_call(
|
||||||
working_set,
|
working_set,
|
||||||
@ -1755,7 +1758,7 @@ pub fn parse_overlay(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let call = match working_set.find_decl(b"overlay") {
|
let call = match working_set.find_decl(b"overlay", &Type::Any) {
|
||||||
Some(decl_id) => {
|
Some(decl_id) => {
|
||||||
let (call, mut err) = parse_internal_call(
|
let (call, mut err) = parse_internal_call(
|
||||||
working_set,
|
working_set,
|
||||||
@ -1820,7 +1823,7 @@ pub fn parse_overlay_new(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (call, call_span) = match working_set.find_decl(b"overlay new") {
|
let (call, call_span) = match working_set.find_decl(b"overlay new", &Type::Any) {
|
||||||
Some(decl_id) => {
|
Some(decl_id) => {
|
||||||
let (call, mut err) = parse_internal_call(
|
let (call, mut err) = parse_internal_call(
|
||||||
working_set,
|
working_set,
|
||||||
@ -1911,7 +1914,7 @@ pub fn parse_overlay_add(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Allow full import pattern as argument (requires custom naming of module/overlay)
|
// TODO: Allow full import pattern as argument (requires custom naming of module/overlay)
|
||||||
let (call, call_span) = match working_set.find_decl(b"overlay add") {
|
let (call, call_span) = match working_set.find_decl(b"overlay add", &Type::Any) {
|
||||||
Some(decl_id) => {
|
Some(decl_id) => {
|
||||||
let (call, mut err) = parse_internal_call(
|
let (call, mut err) = parse_internal_call(
|
||||||
working_set,
|
working_set,
|
||||||
@ -2098,7 +2101,7 @@ pub fn parse_overlay_remove(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let call = match working_set.find_decl(b"overlay remove") {
|
let call = match working_set.find_decl(b"overlay remove", &Type::Any) {
|
||||||
Some(decl_id) => {
|
Some(decl_id) => {
|
||||||
let (call, mut err) = parse_internal_call(
|
let (call, mut err) = parse_internal_call(
|
||||||
working_set,
|
working_set,
|
||||||
@ -2209,7 +2212,7 @@ pub fn parse_let(
|
|||||||
return (Pipeline::from_vec(vec![garbage(*span)]), Some(err));
|
return (Pipeline::from_vec(vec![garbage(*span)]), Some(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(decl_id) = working_set.find_decl(b"let") {
|
if let Some(decl_id) = working_set.find_decl(b"let", &Type::Any) {
|
||||||
let cmd = working_set.get_decl(decl_id);
|
let cmd = working_set.get_decl(decl_id);
|
||||||
let call_signature = cmd.signature().call_signature();
|
let call_signature = cmd.signature().call_signature();
|
||||||
|
|
||||||
@ -2313,7 +2316,7 @@ pub fn parse_source(
|
|||||||
let name = working_set.get_span_contents(spans[0]);
|
let name = working_set.get_span_contents(spans[0]);
|
||||||
|
|
||||||
if name == b"source" {
|
if name == b"source" {
|
||||||
if let Some(decl_id) = working_set.find_decl(b"source") {
|
if let Some(decl_id) = working_set.find_decl(b"source", &Type::Any) {
|
||||||
let cwd = working_set.get_cwd();
|
let cwd = working_set.get_cwd();
|
||||||
// Is this the right call to be using here?
|
// Is this the right call to be using here?
|
||||||
// Some of the others (`parse_let`) use it, some of them (`parse_hide`) don't.
|
// Some of the others (`parse_let`) use it, some of them (`parse_hide`) don't.
|
||||||
@ -2445,7 +2448,7 @@ pub fn parse_register(
|
|||||||
// Parsing the spans and checking that they match the register signature
|
// Parsing the spans and checking that they match the register signature
|
||||||
// Using a parsed call makes more sense than checking for how many spans are in the call
|
// Using a parsed call makes more sense than checking for how many spans are in the call
|
||||||
// Also, by creating a call, it can be checked if it matches the declaration signature
|
// Also, by creating a call, it can be checked if it matches the declaration signature
|
||||||
let (call, call_span) = match working_set.find_decl(b"register") {
|
let (call, call_span) = match working_set.find_decl(b"register", &Type::Any) {
|
||||||
None => {
|
None => {
|
||||||
return (
|
return (
|
||||||
garbage_pipeline(spans),
|
garbage_pipeline(spans),
|
||||||
|
@ -739,7 +739,10 @@ pub fn parse_internal_call(
|
|||||||
call.decl_id = decl_id;
|
call.decl_id = decl_id;
|
||||||
call.head = command_span;
|
call.head = command_span;
|
||||||
|
|
||||||
let signature = working_set.get_decl(decl_id).signature();
|
let decl = working_set.get_decl(decl_id);
|
||||||
|
let signature = decl.signature();
|
||||||
|
let output = decl.output_type();
|
||||||
|
working_set.found_outputs.push(output);
|
||||||
|
|
||||||
if signature.creates_scope {
|
if signature.creates_scope {
|
||||||
working_set.enter_scope();
|
working_set.enter_scope();
|
||||||
@ -1009,7 +1012,8 @@ pub fn parse_call(
|
|||||||
pos += 1;
|
pos += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut maybe_decl_id = working_set.find_decl(&name);
|
let input = working_set.found_outputs.last().unwrap_or(&Type::Any);
|
||||||
|
let mut maybe_decl_id = working_set.find_decl(&name, input);
|
||||||
|
|
||||||
while maybe_decl_id.is_none() {
|
while maybe_decl_id.is_none() {
|
||||||
// Find the longest command match
|
// Find the longest command match
|
||||||
@ -1031,7 +1035,7 @@ pub fn parse_call(
|
|||||||
name.extend(name_part);
|
name.extend(name_part);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
maybe_decl_id = working_set.find_decl(&name);
|
maybe_decl_id = working_set.find_decl(&name, input);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(decl_id) = maybe_decl_id {
|
if let Some(decl_id) = maybe_decl_id {
|
||||||
@ -2648,7 +2652,7 @@ pub fn parse_shape_name(
|
|||||||
);
|
);
|
||||||
let command_name = trim_quotes(split[1].as_bytes());
|
let command_name = trim_quotes(split[1].as_bytes());
|
||||||
|
|
||||||
let decl_id = working_set.find_decl(command_name);
|
let decl_id = working_set.find_decl(command_name, &Type::Any);
|
||||||
|
|
||||||
if let Some(decl_id) = decl_id {
|
if let Some(decl_id) = decl_id {
|
||||||
return (SyntaxShape::Custom(Box::new(shape), decl_id), err);
|
return (SyntaxShape::Custom(Box::new(shape), decl_id), err);
|
||||||
@ -4511,7 +4515,7 @@ pub fn parse_expression(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let with_env = working_set.find_decl(b"with-env");
|
let with_env = working_set.find_decl(b"with-env", &Type::Any);
|
||||||
|
|
||||||
if !shorthand.is_empty() {
|
if !shorthand.is_empty() {
|
||||||
if let Some(decl_id) = with_env {
|
if let Some(decl_id) = with_env {
|
||||||
@ -4607,7 +4611,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" => {
|
||||||
if let Some(decl_id) = working_set.find_decl(b"alias") {
|
if let Some(decl_id) = working_set.find_decl(b"alias", &Type::Any) {
|
||||||
let (call, _) = parse_internal_call(
|
let (call, _) = parse_internal_call(
|
||||||
working_set,
|
working_set,
|
||||||
lite_command.parts[0],
|
lite_command.parts[0],
|
||||||
@ -4818,8 +4822,9 @@ pub fn parse_block(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if idx == 0 {
|
if idx == 0 {
|
||||||
if let Some(let_decl_id) = working_set.find_decl(b"let") {
|
if let Some(let_decl_id) = working_set.find_decl(b"let", &Type::Any) {
|
||||||
if let Some(let_env_decl_id) = working_set.find_decl(b"let-env") {
|
if let Some(let_env_decl_id) = working_set.find_decl(b"let-env", &Type::Any)
|
||||||
|
{
|
||||||
for expr in pipeline.expressions.iter_mut() {
|
for expr in pipeline.expressions.iter_mut() {
|
||||||
if let Expression {
|
if let Expression {
|
||||||
expr: Expr::Call(call),
|
expr: Expr::Call(call),
|
||||||
@ -5136,7 +5141,7 @@ pub fn discover_captures_in_expr(
|
|||||||
fn wrap_expr_with_collect(working_set: &mut StateWorkingSet, expr: &Expression) -> Expression {
|
fn wrap_expr_with_collect(working_set: &mut StateWorkingSet, expr: &Expression) -> Expression {
|
||||||
let span = expr.span;
|
let span = expr.span;
|
||||||
|
|
||||||
if let Some(decl_id) = working_set.find_decl(b"collect") {
|
if let Some(decl_id) = working_set.find_decl(b"collect", &Type::Any) {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
|
|
||||||
let var_id = working_set.next_var_id();
|
let var_id = working_set.next_var_id();
|
||||||
|
@ -662,3 +662,291 @@ mod range {
|
|||||||
assert!(err.is_some());
|
assert!(err.is_some());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod input_types {
|
||||||
|
use super::*;
|
||||||
|
use nu_protocol::{Category, Type};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct LsTest;
|
||||||
|
|
||||||
|
impl Command for LsTest {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"ls"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Mock ls command"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> nu_protocol::Signature {
|
||||||
|
Signature::build(self.name()).category(Category::Default)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
_engine_state: &EngineState,
|
||||||
|
_stack: &mut Stack,
|
||||||
|
_call: &nu_protocol::ast::Call,
|
||||||
|
_input: nu_protocol::PipelineData,
|
||||||
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct GroupByList;
|
||||||
|
|
||||||
|
impl Command for GroupByList {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"group-by"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Mock group-by command"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> nu_protocol::Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
|
.required("column", SyntaxShape::String, "column name")
|
||||||
|
.category(Category::Default)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
_engine_state: &EngineState,
|
||||||
|
_stack: &mut Stack,
|
||||||
|
_call: &nu_protocol::ast::Call,
|
||||||
|
_input: nu_protocol::PipelineData,
|
||||||
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ToCustom;
|
||||||
|
|
||||||
|
impl Command for ToCustom {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"to-custom"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Mock converter command"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> nu_protocol::Signature {
|
||||||
|
Signature::build(self.name()).category(Category::Custom("custom".into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
_engine_state: &EngineState,
|
||||||
|
_stack: &mut Stack,
|
||||||
|
_call: &nu_protocol::ast::Call,
|
||||||
|
_input: nu_protocol::PipelineData,
|
||||||
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn input_type(&self) -> nu_protocol::Type {
|
||||||
|
Type::Any
|
||||||
|
}
|
||||||
|
|
||||||
|
fn output_type(&self) -> nu_protocol::Type {
|
||||||
|
Type::Custom("custom".into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct GroupByCustom;
|
||||||
|
|
||||||
|
impl Command for GroupByCustom {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"group-by"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Mock custom group-by command"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> nu_protocol::Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
|
.required("column", SyntaxShape::String, "column name")
|
||||||
|
.required("other", SyntaxShape::String, "other value")
|
||||||
|
.category(Category::Custom("custom".into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
_engine_state: &EngineState,
|
||||||
|
_stack: &mut Stack,
|
||||||
|
_call: &nu_protocol::ast::Call,
|
||||||
|
_input: nu_protocol::PipelineData,
|
||||||
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn input_type(&self) -> nu_protocol::Type {
|
||||||
|
Type::Custom("custom".into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn output_type(&self) -> nu_protocol::Type {
|
||||||
|
Type::Custom("custom".into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct AggCustom;
|
||||||
|
|
||||||
|
impl Command for AggCustom {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"agg"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Mock custom agg command"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> nu_protocol::Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
|
.required("operation", SyntaxShape::String, "operation")
|
||||||
|
.category(Category::Custom("custom".into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
_engine_state: &EngineState,
|
||||||
|
_stack: &mut Stack,
|
||||||
|
_call: &nu_protocol::ast::Call,
|
||||||
|
_input: nu_protocol::PipelineData,
|
||||||
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn input_type(&self) -> nu_protocol::Type {
|
||||||
|
Type::Custom("custom".into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_declations(engine_state: &mut EngineState) {
|
||||||
|
let delta = {
|
||||||
|
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||||
|
working_set.add_decl(Box::new(Let));
|
||||||
|
working_set.add_decl(Box::new(AggCustom));
|
||||||
|
working_set.add_decl(Box::new(GroupByCustom));
|
||||||
|
working_set.add_decl(Box::new(GroupByList));
|
||||||
|
working_set.add_decl(Box::new(LsTest));
|
||||||
|
working_set.add_decl(Box::new(ToCustom));
|
||||||
|
working_set.add_decl(Box::new(Let));
|
||||||
|
|
||||||
|
working_set.render()
|
||||||
|
};
|
||||||
|
|
||||||
|
let cwd = std::env::current_dir().expect("Could not get current working directory.");
|
||||||
|
let _ = engine_state.merge_delta(delta, None, &cwd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn call_types_test() {
|
||||||
|
let mut engine_state = EngineState::new();
|
||||||
|
add_declations(&mut engine_state);
|
||||||
|
|
||||||
|
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||||
|
let input = r#"ls | to-custom | group-by name other"#;
|
||||||
|
|
||||||
|
let (block, err) = parse(&mut working_set, None, input.as_bytes(), true, &[]);
|
||||||
|
|
||||||
|
assert!(err.is_none());
|
||||||
|
assert!(block.len() == 1);
|
||||||
|
|
||||||
|
let expressions = &block[0];
|
||||||
|
assert!(expressions.len() == 3);
|
||||||
|
|
||||||
|
match &expressions[0].expr {
|
||||||
|
Expr::Call(call) => {
|
||||||
|
let expected_id = working_set.find_decl(b"ls", &Type::Any).unwrap();
|
||||||
|
assert_eq!(call.decl_id, expected_id)
|
||||||
|
}
|
||||||
|
_ => panic!("Expected expression Call not found"),
|
||||||
|
}
|
||||||
|
|
||||||
|
match &expressions[1].expr {
|
||||||
|
Expr::Call(call) => {
|
||||||
|
let expected_id = working_set.find_decl(b"to-custom", &Type::Any).unwrap();
|
||||||
|
assert_eq!(call.decl_id, expected_id)
|
||||||
|
}
|
||||||
|
_ => panic!("Expected expression Call not found"),
|
||||||
|
}
|
||||||
|
|
||||||
|
match &expressions[2].expr {
|
||||||
|
Expr::Call(call) => {
|
||||||
|
let expected_id = working_set
|
||||||
|
.find_decl(b"group-by", &Type::Custom("custom".into()))
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(call.decl_id, expected_id)
|
||||||
|
}
|
||||||
|
_ => panic!("Expected expression Call not found"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn storing_variable_test() {
|
||||||
|
let mut engine_state = EngineState::new();
|
||||||
|
add_declations(&mut engine_state);
|
||||||
|
|
||||||
|
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||||
|
let input =
|
||||||
|
r#"let a = (ls | to-custom | group-by name other); let b = (1+3); $a | agg sum"#;
|
||||||
|
|
||||||
|
let (block, err) = parse(&mut working_set, None, input.as_bytes(), true, &[]);
|
||||||
|
|
||||||
|
assert!(err.is_none());
|
||||||
|
assert!(block.len() == 3);
|
||||||
|
|
||||||
|
let expressions = &block[2];
|
||||||
|
match &expressions[1].expr {
|
||||||
|
Expr::Call(call) => {
|
||||||
|
let expected_id = working_set
|
||||||
|
.find_decl(b"agg", &Type::Custom("custom".into()))
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(call.decl_id, expected_id)
|
||||||
|
}
|
||||||
|
_ => panic!("Expected expression Call not found"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn call_non_custom_types_test() {
|
||||||
|
let mut engine_state = EngineState::new();
|
||||||
|
add_declations(&mut engine_state);
|
||||||
|
|
||||||
|
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||||
|
let input = r#"ls | group-by name"#;
|
||||||
|
|
||||||
|
let (block, err) = parse(&mut working_set, None, input.as_bytes(), true, &[]);
|
||||||
|
|
||||||
|
assert!(err.is_none());
|
||||||
|
assert!(block.len() == 1);
|
||||||
|
|
||||||
|
let expressions = &block[0];
|
||||||
|
assert!(expressions.len() == 2);
|
||||||
|
|
||||||
|
match &expressions[0].expr {
|
||||||
|
Expr::Call(call) => {
|
||||||
|
let expected_id = working_set.find_decl(b"ls", &Type::Any).unwrap();
|
||||||
|
assert_eq!(call.decl_id, expected_id)
|
||||||
|
}
|
||||||
|
_ => panic!("Expected expression Call not found"),
|
||||||
|
}
|
||||||
|
|
||||||
|
match &expressions[1].expr {
|
||||||
|
Expr::Call(call) => {
|
||||||
|
let expected_id = working_set.find_decl(b"group-by", &Type::Any).unwrap();
|
||||||
|
assert_eq!(call.decl_id, expected_id)
|
||||||
|
}
|
||||||
|
_ => panic!("Expected expression Call not found"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::{ast::Call, BlockId, Example, PipelineData, ShellError, Signature};
|
use crate::{ast::Call, BlockId, Example, PipelineData, ShellError, Signature, Type};
|
||||||
|
|
||||||
use super::{EngineState, Stack};
|
use super::{EngineState, Stack};
|
||||||
|
|
||||||
@ -66,6 +66,20 @@ pub trait Command: Send + Sync + CommandClone {
|
|||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Command input type. The Type is used during parsing to find the
|
||||||
|
// correct internal command with similar names. The input type is
|
||||||
|
// obtained from the previous expression found in the pipeline
|
||||||
|
fn input_type(&self) -> Type {
|
||||||
|
Type::Any
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command output type. The output type is the value from the command
|
||||||
|
// It is used during parsing to find the next command in case there
|
||||||
|
// are commands with similar names
|
||||||
|
fn output_type(&self) -> Type {
|
||||||
|
Type::Any
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CommandClone {
|
pub trait CommandClone {
|
||||||
|
@ -464,9 +464,9 @@ impl EngineState {
|
|||||||
for overlay_frame in self.active_overlays(removed_overlays).iter().rev() {
|
for overlay_frame in self.active_overlays(removed_overlays).iter().rev() {
|
||||||
visibility.append(&overlay_frame.visibility);
|
visibility.append(&overlay_frame.visibility);
|
||||||
|
|
||||||
if let Some(decl_id) = overlay_frame.decls.get(name) {
|
if let Some(decl_id) = overlay_frame.get_decl(name, &Type::Any) {
|
||||||
if visibility.is_decl_id_visible(decl_id) {
|
if visibility.is_decl_id_visible(&decl_id) {
|
||||||
return Some(*decl_id);
|
return Some(decl_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -533,9 +533,9 @@ impl EngineState {
|
|||||||
|
|
||||||
for overlay_frame in self.active_overlays(&[]).iter().rev() {
|
for overlay_frame in self.active_overlays(&[]).iter().rev() {
|
||||||
for decl in &overlay_frame.decls {
|
for decl in &overlay_frame.decls {
|
||||||
if overlay_frame.visibility.is_decl_id_visible(decl.1) && predicate(decl.0) {
|
if overlay_frame.visibility.is_decl_id_visible(decl.1) && predicate(&decl.0 .0) {
|
||||||
let command = self.get_decl(*decl.1);
|
let command = self.get_decl(*decl.1);
|
||||||
output.push((decl.0.clone(), Some(command.usage().to_string())));
|
output.push((decl.0 .0.clone(), Some(command.usage().to_string())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -614,7 +614,8 @@ impl EngineState {
|
|||||||
decls_map.extend(new_decls);
|
decls_map.extend(new_decls);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut decls: Vec<(Vec<u8>, DeclId)> = decls_map.into_iter().collect();
|
let mut decls: Vec<(Vec<u8>, DeclId)> =
|
||||||
|
decls_map.into_iter().map(|(v, k)| (v.0, k)).collect();
|
||||||
|
|
||||||
decls.sort_by(|a, b| a.0.cmp(&b.0));
|
decls.sort_by(|a, b| a.0.cmp(&b.0));
|
||||||
decls.into_iter().map(|(_, id)| id)
|
decls.into_iter().map(|(_, id)| id)
|
||||||
@ -743,6 +744,9 @@ pub struct StateWorkingSet<'a> {
|
|||||||
pub permanent_state: &'a EngineState,
|
pub permanent_state: &'a EngineState,
|
||||||
pub delta: StateDelta,
|
pub delta: StateDelta,
|
||||||
pub external_commands: Vec<Vec<u8>>,
|
pub external_commands: Vec<Vec<u8>>,
|
||||||
|
// Internal commands output that the next expression in the pipe will use to select a declaration
|
||||||
|
// that matches the name in the found output
|
||||||
|
pub found_outputs: Vec<Type>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A delta (or change set) between the current global state and a possible future global state. Deltas
|
/// A delta (or change set) between the current global state and a possible future global state. Deltas
|
||||||
@ -867,6 +871,7 @@ impl<'a> StateWorkingSet<'a> {
|
|||||||
delta: StateDelta::new(permanent_state),
|
delta: StateDelta::new(permanent_state),
|
||||||
permanent_state,
|
permanent_state,
|
||||||
external_commands: vec![],
|
external_commands: vec![],
|
||||||
|
found_outputs: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -918,11 +923,13 @@ impl<'a> StateWorkingSet<'a> {
|
|||||||
|
|
||||||
pub fn add_decl(&mut self, decl: Box<dyn Command>) -> DeclId {
|
pub fn add_decl(&mut self, decl: Box<dyn Command>) -> DeclId {
|
||||||
let name = decl.name().as_bytes().to_vec();
|
let name = decl.name().as_bytes().to_vec();
|
||||||
|
let input_type = decl.input_type();
|
||||||
|
|
||||||
self.delta.decls.push(decl);
|
self.delta.decls.push(decl);
|
||||||
let decl_id = self.num_decls() - 1;
|
let decl_id = self.num_decls() - 1;
|
||||||
|
|
||||||
self.last_overlay_mut().decls.insert(name, decl_id);
|
self.last_overlay_mut()
|
||||||
|
.insert_decl(name, input_type, decl_id);
|
||||||
|
|
||||||
decl_id
|
decl_id
|
||||||
}
|
}
|
||||||
@ -931,7 +938,7 @@ impl<'a> StateWorkingSet<'a> {
|
|||||||
let overlay_frame = self.last_overlay_mut();
|
let overlay_frame = self.last_overlay_mut();
|
||||||
|
|
||||||
for (name, decl_id) in decls {
|
for (name, decl_id) in decls {
|
||||||
overlay_frame.decls.insert(name, decl_id);
|
overlay_frame.insert_decl(name, Type::Any, decl_id);
|
||||||
overlay_frame.visibility.use_decl_id(&decl_id);
|
overlay_frame.visibility.use_decl_id(&decl_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -968,7 +975,7 @@ impl<'a> StateWorkingSet<'a> {
|
|||||||
let overlay_frame = self.last_overlay_mut();
|
let overlay_frame = self.last_overlay_mut();
|
||||||
|
|
||||||
if let Some(decl_id) = overlay_frame.predecls.remove(name) {
|
if let Some(decl_id) = overlay_frame.predecls.remove(name) {
|
||||||
overlay_frame.decls.insert(name.into(), decl_id);
|
overlay_frame.insert_decl(name.into(), Type::Any, decl_id);
|
||||||
|
|
||||||
return Some(decl_id);
|
return Some(decl_id);
|
||||||
}
|
}
|
||||||
@ -998,11 +1005,11 @@ impl<'a> StateWorkingSet<'a> {
|
|||||||
|
|
||||||
visibility.append(&overlay_frame.visibility);
|
visibility.append(&overlay_frame.visibility);
|
||||||
|
|
||||||
if let Some(decl_id) = overlay_frame.decls.get(name) {
|
if let Some(decl_id) = overlay_frame.get_decl(name, &Type::Any) {
|
||||||
if visibility.is_decl_id_visible(decl_id) {
|
if visibility.is_decl_id_visible(&decl_id) {
|
||||||
// Hide decl only if it's not already hidden
|
// Hide decl only if it's not already hidden
|
||||||
overlay_frame.visibility.hide_decl_id(decl_id);
|
overlay_frame.visibility.hide_decl_id(&decl_id);
|
||||||
return Some(*decl_id);
|
return Some(decl_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1018,11 +1025,11 @@ impl<'a> StateWorkingSet<'a> {
|
|||||||
{
|
{
|
||||||
visibility.append(&overlay_frame.visibility);
|
visibility.append(&overlay_frame.visibility);
|
||||||
|
|
||||||
if let Some(decl_id) = overlay_frame.decls.get(name) {
|
if let Some(decl_id) = overlay_frame.get_decl(name, &Type::Any) {
|
||||||
if visibility.is_decl_id_visible(decl_id) {
|
if visibility.is_decl_id_visible(&decl_id) {
|
||||||
// Hide decl only if it's not already hidden
|
// Hide decl only if it's not already hidden
|
||||||
self.last_overlay_mut().visibility.hide_decl_id(decl_id);
|
self.last_overlay_mut().visibility.hide_decl_id(&decl_id);
|
||||||
return Some(*decl_id);
|
return Some(decl_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1254,7 +1261,7 @@ impl<'a> StateWorkingSet<'a> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_decl(&self, name: &[u8]) -> Option<DeclId> {
|
pub fn find_decl(&self, name: &[u8], input: &Type) -> Option<DeclId> {
|
||||||
let mut removed_overlays = vec![];
|
let mut removed_overlays = vec![];
|
||||||
|
|
||||||
let mut visibility: Visibility = Visibility::new();
|
let mut visibility: Visibility = Visibility::new();
|
||||||
@ -1280,9 +1287,9 @@ impl<'a> StateWorkingSet<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(decl_id) = overlay_frame.decls.get(name) {
|
if let Some(decl_id) = overlay_frame.get_decl(name, input) {
|
||||||
if visibility.is_decl_id_visible(decl_id) {
|
if visibility.is_decl_id_visible(&decl_id) {
|
||||||
return Some(*decl_id);
|
return Some(decl_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1297,9 +1304,9 @@ impl<'a> StateWorkingSet<'a> {
|
|||||||
{
|
{
|
||||||
visibility.append(&overlay_frame.visibility);
|
visibility.append(&overlay_frame.visibility);
|
||||||
|
|
||||||
if let Some(decl_id) = overlay_frame.decls.get(name) {
|
if let Some(decl_id) = overlay_frame.get_decl(name, input) {
|
||||||
if visibility.is_decl_id_visible(decl_id) {
|
if visibility.is_decl_id_visible(&decl_id) {
|
||||||
return Some(*decl_id);
|
return Some(decl_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1384,7 +1391,7 @@ impl<'a> StateWorkingSet<'a> {
|
|||||||
.rev()
|
.rev()
|
||||||
{
|
{
|
||||||
for decl in &overlay_frame.decls {
|
for decl in &overlay_frame.decls {
|
||||||
if decl.0.starts_with(name) {
|
if decl.0 .0.starts_with(name) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1398,7 +1405,7 @@ impl<'a> StateWorkingSet<'a> {
|
|||||||
.rev()
|
.rev()
|
||||||
{
|
{
|
||||||
for decl in &overlay_frame.decls {
|
for decl in &overlay_frame.decls {
|
||||||
if decl.0.starts_with(name) {
|
if decl.0 .0.starts_with(name) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1562,9 +1569,10 @@ impl<'a> StateWorkingSet<'a> {
|
|||||||
let overlay_frame = scope_frame.get_overlay(*overlay_id);
|
let overlay_frame = scope_frame.get_overlay(*overlay_id);
|
||||||
|
|
||||||
for decl in &overlay_frame.decls {
|
for decl in &overlay_frame.decls {
|
||||||
if overlay_frame.visibility.is_decl_id_visible(decl.1) && predicate(decl.0) {
|
if overlay_frame.visibility.is_decl_id_visible(decl.1) && predicate(&decl.0 .0)
|
||||||
|
{
|
||||||
let command = self.get_decl(*decl.1);
|
let command = self.get_decl(*decl.1);
|
||||||
output.push((decl.0.clone(), Some(command.usage().to_string())));
|
output.push((decl.0 .0.clone(), Some(command.usage().to_string())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1718,8 +1726,8 @@ impl<'a> StateWorkingSet<'a> {
|
|||||||
if let Some(overlay_id) = self.permanent_state.find_overlay(name) {
|
if let Some(overlay_id) = self.permanent_state.find_overlay(name) {
|
||||||
let overlay_frame = self.permanent_state.get_overlay(overlay_id);
|
let overlay_frame = self.permanent_state.get_overlay(overlay_id);
|
||||||
|
|
||||||
for (decl_name, decl_id) in &overlay_frame.decls {
|
for (decl_key, decl_id) in &overlay_frame.decls {
|
||||||
result.insert(decl_name.to_owned(), *decl_id);
|
result.insert(decl_key.0.to_owned(), *decl_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1727,8 +1735,8 @@ impl<'a> StateWorkingSet<'a> {
|
|||||||
if let Some(overlay_id) = scope_frame.find_overlay(name) {
|
if let Some(overlay_id) = scope_frame.find_overlay(name) {
|
||||||
let overlay_frame = scope_frame.get_overlay(overlay_id);
|
let overlay_frame = scope_frame.get_overlay(overlay_id);
|
||||||
|
|
||||||
for (decl_name, decl_id) in &overlay_frame.decls {
|
for (decl_key, decl_id) in &overlay_frame.decls {
|
||||||
result.insert(decl_name.to_owned(), *decl_id);
|
result.insert(decl_key.0.to_owned(), *decl_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
|
use crate::{AliasId, DeclId, ModuleId, OverlayId, Type, VarId};
|
||||||
|
use std::borrow::Borrow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
use crate::{AliasId, DeclId, ModuleId, OverlayId, VarId};
|
|
||||||
|
|
||||||
pub static DEFAULT_OVERLAY_NAME: &str = "zero";
|
pub static DEFAULT_OVERLAY_NAME: &str = "zero";
|
||||||
|
|
||||||
@ -199,7 +200,7 @@ impl ScopeFrame {
|
|||||||
pub struct OverlayFrame {
|
pub struct OverlayFrame {
|
||||||
pub vars: HashMap<Vec<u8>, VarId>,
|
pub vars: HashMap<Vec<u8>, VarId>,
|
||||||
pub predecls: HashMap<Vec<u8>, DeclId>, // temporary storage for predeclarations
|
pub predecls: HashMap<Vec<u8>, DeclId>, // temporary storage for predeclarations
|
||||||
pub decls: HashMap<Vec<u8>, DeclId>,
|
pub decls: HashMap<(Vec<u8>, Type), DeclId>,
|
||||||
pub aliases: HashMap<Vec<u8>, AliasId>,
|
pub aliases: HashMap<Vec<u8>, AliasId>,
|
||||||
pub modules: HashMap<Vec<u8>, ModuleId>,
|
pub modules: HashMap<Vec<u8>, ModuleId>,
|
||||||
pub visibility: Visibility,
|
pub visibility: Visibility,
|
||||||
@ -218,4 +219,58 @@ impl OverlayFrame {
|
|||||||
origin,
|
origin,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn insert_decl(&mut self, name: Vec<u8>, input: Type, decl_id: DeclId) -> Option<DeclId> {
|
||||||
|
self.decls.insert((name, input), decl_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_decl(&self, name: &[u8], input: &Type) -> Option<DeclId> {
|
||||||
|
self.decls.get(&(name, input) as &dyn DeclKey).cloned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait DeclKey {
|
||||||
|
fn name(&self) -> &[u8];
|
||||||
|
fn input(&self) -> &Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for dyn DeclKey + '_ {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.name().hash(state);
|
||||||
|
self.input().hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for dyn DeclKey + '_ {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.name() == other.name() && self.input() == other.input()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for dyn DeclKey + '_ {}
|
||||||
|
|
||||||
|
impl<'a> DeclKey for (&'a [u8], &Type) {
|
||||||
|
fn name(&self) -> &[u8] {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn input(&self) -> &Type {
|
||||||
|
self.1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeclKey for (Vec<u8>, Type) {
|
||||||
|
fn name(&self) -> &[u8] {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn input(&self) -> &Type {
|
||||||
|
&self.1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Borrow<dyn DeclKey + 'a> for (Vec<u8>, Type) {
|
||||||
|
fn borrow(&self) -> &(dyn DeclKey + 'a) {
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ use std::fmt::Display;
|
|||||||
|
|
||||||
use crate::SyntaxShape;
|
use crate::SyntaxShape;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
Int,
|
Int,
|
||||||
Float,
|
Float,
|
||||||
@ -25,7 +25,7 @@ pub enum Type {
|
|||||||
Any,
|
Any,
|
||||||
Error,
|
Error,
|
||||||
Binary,
|
Binary,
|
||||||
Custom,
|
Custom(String),
|
||||||
Signature,
|
Signature,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ impl Type {
|
|||||||
Type::Any => SyntaxShape::Any,
|
Type::Any => SyntaxShape::Any,
|
||||||
Type::Error => SyntaxShape::Any,
|
Type::Error => SyntaxShape::Any,
|
||||||
Type::Binary => SyntaxShape::Binary,
|
Type::Binary => SyntaxShape::Binary,
|
||||||
Type::Custom => SyntaxShape::Any,
|
Type::Custom(_) => SyntaxShape::Any,
|
||||||
Type::Signature => SyntaxShape::Signature,
|
Type::Signature => SyntaxShape::Signature,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,7 +95,7 @@ impl Display for Type {
|
|||||||
Type::Any => write!(f, "any"),
|
Type::Any => write!(f, "any"),
|
||||||
Type::Error => write!(f, "error"),
|
Type::Error => write!(f, "error"),
|
||||||
Type::Binary => write!(f, "binary"),
|
Type::Binary => write!(f, "binary"),
|
||||||
Type::Custom => write!(f, "custom"),
|
Type::Custom(custom) => write!(f, "custom<{}>", custom),
|
||||||
Type::Signature => write!(f, "signature"),
|
Type::Signature => write!(f, "signature"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -417,7 +417,7 @@ impl Value {
|
|||||||
Value::Error { .. } => Type::Error,
|
Value::Error { .. } => Type::Error,
|
||||||
Value::Binary { .. } => Type::Binary,
|
Value::Binary { .. } => Type::Binary,
|
||||||
Value::CellPath { .. } => Type::CellPath,
|
Value::CellPath { .. } => Type::CellPath,
|
||||||
Value::CustomValue { .. } => Type::Custom,
|
Value::CustomValue { val, .. } => Type::Custom(val.typetag_name().into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user