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

@ -1,6 +1,6 @@
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};
@ -66,6 +66,20 @@ pub trait Command: Send + Sync + CommandClone {
fn search_terms(&self) -> Vec<&str> {
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 {

View File

@ -464,9 +464,9 @@ impl EngineState {
for overlay_frame in self.active_overlays(removed_overlays).iter().rev() {
visibility.append(&overlay_frame.visibility);
if let Some(decl_id) = overlay_frame.decls.get(name) {
if visibility.is_decl_id_visible(decl_id) {
return Some(*decl_id);
if let Some(decl_id) = overlay_frame.get_decl(name, &Type::Any) {
if visibility.is_decl_id_visible(&decl_id) {
return Some(decl_id);
}
}
}
@ -533,9 +533,9 @@ impl EngineState {
for overlay_frame in self.active_overlays(&[]).iter().rev() {
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);
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);
}
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.into_iter().map(|(_, id)| id)
@ -743,6 +744,9 @@ pub struct StateWorkingSet<'a> {
pub permanent_state: &'a EngineState,
pub delta: StateDelta,
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
@ -867,6 +871,7 @@ impl<'a> StateWorkingSet<'a> {
delta: StateDelta::new(permanent_state),
permanent_state,
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 {
let name = decl.name().as_bytes().to_vec();
let input_type = decl.input_type();
self.delta.decls.push(decl);
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
}
@ -931,7 +938,7 @@ impl<'a> StateWorkingSet<'a> {
let overlay_frame = self.last_overlay_mut();
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);
}
}
@ -968,7 +975,7 @@ impl<'a> StateWorkingSet<'a> {
let overlay_frame = self.last_overlay_mut();
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);
}
@ -998,11 +1005,11 @@ impl<'a> StateWorkingSet<'a> {
visibility.append(&overlay_frame.visibility);
if let Some(decl_id) = overlay_frame.decls.get(name) {
if visibility.is_decl_id_visible(decl_id) {
if let Some(decl_id) = overlay_frame.get_decl(name, &Type::Any) {
if visibility.is_decl_id_visible(&decl_id) {
// Hide decl only if it's not already hidden
overlay_frame.visibility.hide_decl_id(decl_id);
return Some(*decl_id);
overlay_frame.visibility.hide_decl_id(&decl_id);
return Some(decl_id);
}
}
}
@ -1018,11 +1025,11 @@ impl<'a> StateWorkingSet<'a> {
{
visibility.append(&overlay_frame.visibility);
if let Some(decl_id) = overlay_frame.decls.get(name) {
if visibility.is_decl_id_visible(decl_id) {
if let Some(decl_id) = overlay_frame.get_decl(name, &Type::Any) {
if visibility.is_decl_id_visible(&decl_id) {
// Hide decl only if it's not already hidden
self.last_overlay_mut().visibility.hide_decl_id(decl_id);
return Some(*decl_id);
self.last_overlay_mut().visibility.hide_decl_id(&decl_id);
return Some(decl_id);
}
}
}
@ -1254,7 +1261,7 @@ impl<'a> StateWorkingSet<'a> {
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 visibility: Visibility = Visibility::new();
@ -1280,9 +1287,9 @@ impl<'a> StateWorkingSet<'a> {
}
}
if let Some(decl_id) = overlay_frame.decls.get(name) {
if visibility.is_decl_id_visible(decl_id) {
return Some(*decl_id);
if let Some(decl_id) = overlay_frame.get_decl(name, input) {
if visibility.is_decl_id_visible(&decl_id) {
return Some(decl_id);
}
}
}
@ -1297,9 +1304,9 @@ impl<'a> StateWorkingSet<'a> {
{
visibility.append(&overlay_frame.visibility);
if let Some(decl_id) = overlay_frame.decls.get(name) {
if visibility.is_decl_id_visible(decl_id) {
return Some(*decl_id);
if let Some(decl_id) = overlay_frame.get_decl(name, input) {
if visibility.is_decl_id_visible(&decl_id) {
return Some(decl_id);
}
}
}
@ -1384,7 +1391,7 @@ impl<'a> StateWorkingSet<'a> {
.rev()
{
for decl in &overlay_frame.decls {
if decl.0.starts_with(name) {
if decl.0 .0.starts_with(name) {
return true;
}
}
@ -1398,7 +1405,7 @@ impl<'a> StateWorkingSet<'a> {
.rev()
{
for decl in &overlay_frame.decls {
if decl.0.starts_with(name) {
if decl.0 .0.starts_with(name) {
return true;
}
}
@ -1562,9 +1569,10 @@ impl<'a> StateWorkingSet<'a> {
let overlay_frame = scope_frame.get_overlay(*overlay_id);
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);
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) {
let overlay_frame = self.permanent_state.get_overlay(overlay_id);
for (decl_name, decl_id) in &overlay_frame.decls {
result.insert(decl_name.to_owned(), *decl_id);
for (decl_key, decl_id) in &overlay_frame.decls {
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) {
let overlay_frame = scope_frame.get_overlay(overlay_id);
for (decl_name, decl_id) in &overlay_frame.decls {
result.insert(decl_name.to_owned(), *decl_id);
for (decl_key, decl_id) in &overlay_frame.decls {
result.insert(decl_key.0.to_owned(), *decl_id);
}
}
}

View File

@ -1,6 +1,7 @@
use crate::{AliasId, DeclId, ModuleId, OverlayId, Type, VarId};
use std::borrow::Borrow;
use std::collections::HashMap;
use crate::{AliasId, DeclId, ModuleId, OverlayId, VarId};
use std::hash::{Hash, Hasher};
pub static DEFAULT_OVERLAY_NAME: &str = "zero";
@ -199,7 +200,7 @@ impl ScopeFrame {
pub struct OverlayFrame {
pub vars: HashMap<Vec<u8>, VarId>,
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 modules: HashMap<Vec<u8>, ModuleId>,
pub visibility: Visibility,
@ -218,4 +219,58 @@ impl OverlayFrame {
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
}
}

View File

@ -4,7 +4,7 @@ use std::fmt::Display;
use crate::SyntaxShape;
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub enum Type {
Int,
Float,
@ -25,7 +25,7 @@ pub enum Type {
Any,
Error,
Binary,
Custom,
Custom(String),
Signature,
}
@ -51,7 +51,7 @@ impl Type {
Type::Any => SyntaxShape::Any,
Type::Error => SyntaxShape::Any,
Type::Binary => SyntaxShape::Binary,
Type::Custom => SyntaxShape::Any,
Type::Custom(_) => SyntaxShape::Any,
Type::Signature => SyntaxShape::Signature,
}
}
@ -95,7 +95,7 @@ impl Display for Type {
Type::Any => write!(f, "any"),
Type::Error => write!(f, "error"),
Type::Binary => write!(f, "binary"),
Type::Custom => write!(f, "custom"),
Type::Custom(custom) => write!(f, "custom<{}>", custom),
Type::Signature => write!(f, "signature"),
}
}

View File

@ -417,7 +417,7 @@ impl Value {
Value::Error { .. } => Type::Error,
Value::Binary { .. } => Type::Binary,
Value::CellPath { .. } => Type::CellPath,
Value::CustomValue { .. } => Type::Custom,
Value::CustomValue { val, .. } => Type::Custom(val.typetag_name().into()),
}
}