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:
Fernando Herrera
2022-06-10 10:59:35 -05:00
committed by GitHub
parent 9d10007085
commit d5b99ae316
12 changed files with 523 additions and 149 deletions

View File

@ -115,7 +115,7 @@ pub fn parse_for(
// 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
// 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 => {
return (
garbage(spans[0]),
@ -284,7 +284,7 @@ pub fn parse_def(
// 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
// 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 => {
return (
garbage_pipeline(spans),
@ -427,7 +427,7 @@ pub fn parse_extern(
// 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
// 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 => {
return (
garbage_pipeline(spans),
@ -520,7 +520,7 @@ pub fn parse_alias(
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(
working_set,
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
} else {
return (
@ -655,18 +655,19 @@ pub fn parse_export(
parse_def(working_set, &lite_command, expand_aliases_denylist);
error = error.or(err);
let export_def_decl_id = if let Some(id) = working_set.find_decl(b"export def") {
id
} else {
return (
garbage_pipeline(spans),
None,
Some(ParseError::InternalError(
"missing 'export def' command".into(),
export_span,
)),
);
};
let export_def_decl_id =
if let Some(id) = working_set.find_decl(b"export def", &Type::Any) {
id
} else {
return (
garbage_pipeline(spans),
None,
Some(ParseError::InternalError(
"missing 'export def' command".into(),
export_span,
)),
);
};
// Trying to warp the 'def' call into the 'export def' in a very clumsy way
if let Some(Expression {
@ -690,7 +691,7 @@ pub fn parse_export(
if error.is_none() {
let decl_name = working_set.get_span_contents(spans[2]);
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))
} else {
error = error.or_else(|| {
@ -714,19 +715,19 @@ pub fn parse_export(
parse_def(working_set, &lite_command, expand_aliases_denylist);
error = error.or(err);
let export_def_decl_id = if let Some(id) = working_set.find_decl(b"export def-env")
{
id
} else {
return (
garbage_pipeline(spans),
None,
Some(ParseError::InternalError(
"missing 'export def-env' command".into(),
export_span,
)),
);
};
let export_def_decl_id =
if let Some(id) = working_set.find_decl(b"export def-env", &Type::Any) {
id
} else {
return (
garbage_pipeline(spans),
None,
Some(ParseError::InternalError(
"missing 'export def-env' command".into(),
export_span,
)),
);
};
// Trying to warp the 'def' call into the 'export def' in a very clumsy way
if let Some(Expression {
@ -750,7 +751,7 @@ pub fn parse_export(
if error.is_none() {
let decl_name = working_set.get_span_contents(spans[2]);
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))
} else {
error = error.or_else(|| {
@ -774,18 +775,19 @@ pub fn parse_export(
parse_extern(working_set, &lite_command, expand_aliases_denylist);
error = error.or(err);
let export_def_decl_id = if let Some(id) = working_set.find_decl(b"export extern") {
id
} else {
return (
garbage_pipeline(spans),
None,
Some(ParseError::InternalError(
"missing 'export extern' command".into(),
export_span,
)),
);
};
let export_def_decl_id =
if let Some(id) = working_set.find_decl(b"export extern", &Type::Any) {
id
} else {
return (
garbage_pipeline(spans),
None,
Some(ParseError::InternalError(
"missing 'export extern' command".into(),
export_span,
)),
);
};
// Trying to warp the 'def' call into the 'export def' in a very clumsy way
if let Some(Expression {
@ -809,7 +811,7 @@ pub fn parse_export(
if error.is_none() {
let decl_name = working_set.get_span_contents(spans[2]);
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))
} else {
error = error.or_else(|| {
@ -833,19 +835,19 @@ pub fn parse_export(
parse_alias(working_set, &lite_command.parts, expand_aliases_denylist);
error = error.or(err);
let export_alias_decl_id = if let Some(id) = working_set.find_decl(b"export alias")
{
id
} else {
return (
garbage_pipeline(spans),
None,
Some(ParseError::InternalError(
"missing 'export alias' command".into(),
export_span,
)),
);
};
let export_alias_decl_id =
if let Some(id) = working_set.find_decl(b"export alias", &Type::Any) {
id
} else {
return (
garbage_pipeline(spans),
None,
Some(ParseError::InternalError(
"missing 'export alias' command".into(),
export_span,
)),
);
};
// Trying to warp the 'alias' call into the 'export alias' in a very clumsy way
if let Some(Expression {
@ -885,7 +887,7 @@ pub fn parse_export(
}
}
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;
} else {
return (
@ -1190,7 +1192,7 @@ pub fn parse_module(
};
let module_decl_id = working_set
.find_decl(b"module")
.find_decl(b"module", &Type::Any)
.expect("internal error: missing module command");
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) => {
let (call, mut err) = parse_internal_call(
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) => {
let (call, mut err) = parse_internal_call(
working_set,
@ -1542,33 +1544,34 @@ pub fn parse_hide(
error = error.or(err);
}
let (is_module, module) =
if let Some(module_id) = working_set.find_module(&import_pattern.head.name) {
(true, working_set.get_module(module_id).clone())
} else if import_pattern.members.is_empty() {
// The pattern head can be:
if let Some(id) = working_set.find_alias(&import_pattern.head.name) {
// an alias,
let mut module = Module::new();
module.add_alias(&import_pattern.head.name, id);
let (is_module, module) = if let Some(module_id) =
working_set.find_module(&import_pattern.head.name)
{
(true, working_set.get_module(module_id).clone())
} else if import_pattern.members.is_empty() {
// The pattern head can be:
if let Some(id) = working_set.find_alias(&import_pattern.head.name) {
// an alias,
let mut module = Module::new();
module.add_alias(&import_pattern.head.name, id);
(false, module)
} else if let Some(id) = working_set.find_decl(&import_pattern.head.name) {
// a custom command,
let mut module = Module::new();
module.add_decl(&import_pattern.head.name, id);
(false, module)
} else if let Some(id) = working_set.find_decl(&import_pattern.head.name, &Type::Any) {
// a custom command,
let mut module = Module::new();
module.add_decl(&import_pattern.head.name, id);
(false, module)
} else {
// , or it could be an env var (handled by the engine)
(false, Module::new())
}
(false, module)
} else {
return (
garbage_pipeline(spans),
Some(ParseError::ModuleNotFound(spans[1])),
);
};
// , or it could be an env var (handled by the engine)
(false, Module::new())
}
} else {
return (
garbage_pipeline(spans),
Some(ParseError::ModuleNotFound(spans[1])),
);
};
// 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() {
@ -1696,7 +1699,7 @@ pub fn parse_overlay(
}
b"list" => {
// 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) => {
let (call, mut err) = parse_internal_call(
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) => {
let (call, mut err) = parse_internal_call(
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) => {
let (call, mut err) = parse_internal_call(
working_set,
@ -1911,7 +1914,7 @@ pub fn parse_overlay_add(
}
// 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) => {
let (call, mut err) = parse_internal_call(
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) => {
let (call, mut err) = parse_internal_call(
working_set,
@ -2209,7 +2212,7 @@ pub fn parse_let(
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 call_signature = cmd.signature().call_signature();
@ -2313,7 +2316,7 @@ pub fn parse_source(
let name = working_set.get_span_contents(spans[0]);
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();
// Is this the right call to be using here?
// 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
// 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
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 => {
return (
garbage_pipeline(spans),

View File

@ -739,7 +739,10 @@ pub fn parse_internal_call(
call.decl_id = decl_id;
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 {
working_set.enter_scope();
@ -1009,7 +1012,8 @@ pub fn parse_call(
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() {
// Find the longest command match
@ -1031,7 +1035,7 @@ pub fn parse_call(
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 {
@ -2648,7 +2652,7 @@ pub fn parse_shape_name(
);
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 {
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 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"source" => parse_source(working_set, &lite_command.parts, expand_aliases_denylist),
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(
working_set,
lite_command.parts[0],
@ -4818,8 +4822,9 @@ pub fn parse_block(
);
if idx == 0 {
if let Some(let_decl_id) = working_set.find_decl(b"let") {
if let Some(let_env_decl_id) = working_set.find_decl(b"let-env") {
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", &Type::Any)
{
for expr in pipeline.expressions.iter_mut() {
if let Expression {
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 {
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 var_id = working_set.next_var_id();