nushell/src/parser/registry.rs
Jonathan Turner 193b00764b
Stream support (#812)
* Moves off of draining between filters. Instead, the sink will pull on the stream, and will drain element-wise. This moves the whole stream to being lazy.
* Adds ctrl-c support and connects it into some of the key points where we pull on the stream. If a ctrl-c is detect, we immediately halt pulling on the stream and return to the prompt.
* Moves away from having a SourceMap where anchor locations are stored. Now AnchorLocation is kept directly in the Tag.
* To make this possible, split tag and span. Span is largely used in the parser and is copyable. Tag is now no longer copyable.
2019-10-13 17:12:43 +13:00

322 lines
8.3 KiB
Rust

// TODO: Temporary redirect
pub(crate) use crate::context::CommandRegistry;
use crate::evaluate::{evaluate_baseline_expr, Scope};
use crate::parser::{hir, hir::SyntaxShape};
use crate::prelude::*;
use derive_new::new;
use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug, Serialize, Deserialize, Clone)]
pub enum NamedType {
Switch,
Mandatory(SyntaxShape),
Optional(SyntaxShape),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum PositionalType {
Mandatory(String, SyntaxShape),
Optional(String, SyntaxShape),
}
impl PositionalType {
pub fn mandatory(name: &str, ty: SyntaxShape) -> PositionalType {
PositionalType::Mandatory(name.to_string(), ty)
}
pub fn mandatory_any(name: &str) -> PositionalType {
PositionalType::Mandatory(name.to_string(), SyntaxShape::Any)
}
pub fn mandatory_block(name: &str) -> PositionalType {
PositionalType::Mandatory(name.to_string(), SyntaxShape::Block)
}
pub fn optional(name: &str, ty: SyntaxShape) -> PositionalType {
PositionalType::Optional(name.to_string(), ty)
}
pub fn optional_any(name: &str) -> PositionalType {
PositionalType::Optional(name.to_string(), SyntaxShape::Any)
}
pub(crate) fn name(&self) -> &str {
match self {
PositionalType::Mandatory(s, _) => s,
PositionalType::Optional(s, _) => s,
}
}
pub(crate) fn syntax_type(&self) -> SyntaxShape {
match *self {
PositionalType::Mandatory(_, t) => t,
PositionalType::Optional(_, t) => t,
}
}
}
#[derive(Debug, Serialize, Deserialize, Clone, new)]
pub struct Signature {
pub name: String,
#[new(default)]
pub usage: String,
#[new(default)]
pub positional: Vec<PositionalType>,
#[new(value = "None")]
pub rest_positional: Option<SyntaxShape>,
#[new(default)]
pub named: IndexMap<String, NamedType>,
#[new(value = "false")]
pub is_filter: bool,
}
impl Signature {
pub fn build(name: impl Into<String>) -> Signature {
Signature::new(name.into())
}
pub fn desc(mut self, usage: impl Into<String>) -> Signature {
self.usage = usage.into();
self
}
pub fn required(mut self, name: impl Into<String>, ty: impl Into<SyntaxShape>) -> Signature {
self.positional
.push(PositionalType::Mandatory(name.into(), ty.into()));
self
}
pub fn optional(mut self, name: impl Into<String>, ty: impl Into<SyntaxShape>) -> Signature {
self.positional
.push(PositionalType::Optional(name.into(), ty.into()));
self
}
pub fn named(mut self, name: impl Into<String>, ty: impl Into<SyntaxShape>) -> Signature {
self.named
.insert(name.into(), NamedType::Optional(ty.into()));
self
}
pub fn required_named(
mut self,
name: impl Into<String>,
ty: impl Into<SyntaxShape>,
) -> Signature {
self.named
.insert(name.into(), NamedType::Mandatory(ty.into()));
self
}
pub fn switch(mut self, name: impl Into<String>) -> Signature {
self.named.insert(name.into(), NamedType::Switch);
self
}
pub fn filter(mut self) -> Signature {
self.is_filter = true;
self
}
pub fn rest(mut self, ty: SyntaxShape) -> Signature {
self.rest_positional = Some(ty);
self
}
}
#[derive(Debug, Default, new, Serialize, Deserialize, Clone)]
pub struct EvaluatedArgs {
pub positional: Option<Vec<Tagged<Value>>>,
pub named: Option<IndexMap<String, Tagged<Value>>>,
}
impl EvaluatedArgs {
pub fn slice_from(&self, from: usize) -> Vec<Tagged<Value>> {
let positional = &self.positional;
match positional {
None => vec![],
Some(list) => list[from..].to_vec(),
}
}
}
#[derive(new)]
pub struct DebugEvaluatedPositional<'a> {
positional: &'a Option<Vec<Tagged<Value>>>,
}
impl fmt::Debug for DebugEvaluatedPositional<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self.positional {
None => write!(f, "None"),
Some(positional) => f
.debug_list()
.entries(positional.iter().map(|p| p.debug()))
.finish(),
}
}
}
#[derive(new)]
pub struct DebugEvaluatedNamed<'a> {
named: &'a Option<IndexMap<String, Tagged<Value>>>,
}
impl fmt::Debug for DebugEvaluatedNamed<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self.named {
None => write!(f, "None"),
Some(named) => f
.debug_map()
.entries(named.iter().map(|(k, v)| (k, v.debug())))
.finish(),
}
}
}
pub struct DebugEvaluatedArgs<'a> {
args: &'a EvaluatedArgs,
}
impl fmt::Debug for DebugEvaluatedArgs<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut s = f.debug_struct("Args");
s.field(
"positional",
&DebugEvaluatedPositional::new(&self.args.positional),
);
s.field("named", &DebugEvaluatedNamed::new(&self.args.named));
s.finish()
}
}
impl EvaluatedArgs {
pub fn debug(&self) -> DebugEvaluatedArgs<'_> {
DebugEvaluatedArgs { args: self }
}
pub fn nth(&self, pos: usize) -> Option<&Tagged<Value>> {
match &self.positional {
None => None,
Some(array) => array.iter().nth(pos),
}
}
pub fn expect_nth(&self, pos: usize) -> Result<&Tagged<Value>, ShellError> {
match &self.positional {
None => Err(ShellError::unimplemented("Better error: expect_nth")),
Some(array) => match array.iter().nth(pos) {
None => Err(ShellError::unimplemented("Better error: expect_nth")),
Some(item) => Ok(item),
},
}
}
pub fn len(&self) -> usize {
match &self.positional {
None => 0,
Some(array) => array.len(),
}
}
pub fn has(&self, name: &str) -> bool {
match &self.named {
None => false,
Some(named) => named.contains_key(name),
}
}
pub fn get(&self, name: &str) -> Option<&Tagged<Value>> {
match &self.named {
None => None,
Some(named) => named.get(name),
}
}
pub fn positional_iter(&self) -> PositionalIter<'_> {
match &self.positional {
None => PositionalIter::Empty,
Some(v) => {
let iter = v.iter();
PositionalIter::Array(iter)
}
}
}
}
pub enum PositionalIter<'a> {
Empty,
Array(std::slice::Iter<'a, Tagged<Value>>),
}
impl<'a> Iterator for PositionalIter<'a> {
type Item = &'a Tagged<Value>;
fn next(&mut self) -> Option<Self::Item> {
match self {
PositionalIter::Empty => None,
PositionalIter::Array(iter) => iter.next(),
}
}
}
pub(crate) fn evaluate_args(
call: &hir::Call,
registry: &CommandRegistry,
scope: &Scope,
source: &Text,
) -> Result<EvaluatedArgs, ShellError> {
let positional: Result<Option<Vec<_>>, _> = call
.positional()
.as_ref()
.map(|p| {
p.iter()
.map(|e| evaluate_baseline_expr(e, registry, scope, source))
.collect()
})
.transpose();
let positional = positional?;
let named: Result<Option<IndexMap<String, Tagged<Value>>>, ShellError> = call
.named()
.as_ref()
.map(|n| {
let mut results = IndexMap::new();
for (name, value) in n.named.iter() {
match value {
hir::named::NamedValue::PresentSwitch(tag) => {
results.insert(name.clone(), Value::boolean(true).tagged(tag));
}
hir::named::NamedValue::Value(expr) => {
results.insert(
name.clone(),
evaluate_baseline_expr(expr, registry, scope, source)?,
);
}
_ => {}
};
}
Ok(results)
})
.transpose();
let named = named?;
Ok(EvaluatedArgs::new(positional, named))
}