nushell/src/parser/registry.rs
Yehuda Katz 34033afce4 WIP improve error infrastructure
Also simplify commands and reduce papercuts
2019-07-12 19:20:26 -07:00

369 lines
9.9 KiB
Rust

use crate::evaluate::{evaluate_baseline_expr, Scope};
use crate::parser::{hir, hir::ExpressionKindHint, parse_command, CallNode, Spanned};
use crate::prelude::*;
use derive_new::new;
use getset::Getters;
use indexmap::IndexMap;
use log::trace;
use serde::{Deserialize, Serialize};
use std::fmt;
#[allow(unused)]
#[derive(Debug, Serialize, Deserialize)]
pub enum NamedType {
Switch,
Mandatory(NamedValue),
Optional(NamedValue),
}
#[derive(Debug, Serialize, Deserialize)]
pub enum NamedValue {
Single,
#[allow(unused)]
Block,
}
impl NamedValue {
crate fn to_coerce_hint(&self) -> Option<ExpressionKindHint> {
match self {
NamedValue::Single => None,
NamedValue::Block => Some(ExpressionKindHint::Block),
}
}
}
#[allow(unused)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum PositionalType {
Mandatory(String, PositionalValue),
Optional(String, PositionalValue),
}
#[derive(Debug, Clone)]
pub enum PositionalValue {
Value,
Block,
}
impl PositionalType {
crate fn mandatory(name: &str, kind: &str) -> PositionalType {
match kind {
"Block" => PositionalType::Mandatory(name.to_string(), PositionalValue::Block),
_ => PositionalType::Mandatory(name.to_string(), PositionalValue::Value),
}
}
crate fn to_coerce_hint(&self) -> Option<ExpressionKindHint> {
match self {
PositionalType::Mandatory(_, PositionalValue::Block)
| PositionalType::Optional(_, PositionalValue::Block) => {
Some(ExpressionKindHint::Block)
}
_ => None,
}
}
crate fn name(&self) -> &str {
match self {
PositionalType::Mandatory(s, _) => s,
PositionalType::Optional(s, _) => s,
}
}
}
#[derive(Debug, Getters, Serialize, Deserialize)]
#[get = "crate"]
pub struct CommandConfig {
pub name: String,
crate positional: Vec<PositionalType>,
pub rest_positional: bool,
pub named: IndexMap<String, NamedType>,
pub is_filter: bool,
pub is_sink: bool,
pub can_load: Vec<String>,
pub can_save: Vec<String>,
}
#[derive(Debug, Default, new, Serialize, Deserialize)]
pub struct Args {
pub positional: Option<Vec<Spanned<Value>>>,
pub named: Option<IndexMap<String, Spanned<Value>>>,
}
#[derive(new)]
pub struct DebugPositional<'a> {
positional: &'a Option<Vec<Spanned<Value>>>,
}
impl fmt::Debug for DebugPositional<'a> {
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.item().debug()))
.finish(),
}
}
}
#[derive(new)]
pub struct DebugNamed<'a> {
named: &'a Option<IndexMap<String, Spanned<Value>>>,
}
impl fmt::Debug for DebugNamed<'a> {
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.item().debug())))
.finish(),
}
}
}
pub struct DebugArgs<'a> {
args: &'a Args,
}
impl fmt::Debug for DebugArgs<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut s = f.debug_struct("Args");
s.field("positional", &DebugPositional::new(&self.args.positional));
s.field("named", &DebugNamed::new(&self.args.named));
s.finish()
}
}
impl Args {
pub fn debug(&'a self) -> DebugArgs<'a> {
DebugArgs { args: self }
}
pub fn nth(&self, pos: usize) -> Option<&Spanned<Value>> {
match &self.positional {
None => None,
Some(array) => array.iter().nth(pos),
}
}
pub fn expect_nth(&self, pos: usize) -> Result<&Spanned<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<&Spanned<Value>> {
match &self.named {
None => None,
Some(named) => named.get(name),
}
}
pub fn positional_iter(&'a self) -> PositionalIter<'a> {
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, Spanned<Value>>),
}
impl Iterator for PositionalIter<'a> {
type Item = &'a Spanned<Value>;
fn next(&mut self) -> Option<Self::Item> {
match self {
PositionalIter::Empty => None,
PositionalIter::Array(iter) => iter.next(),
}
}
}
impl CommandConfig {
crate fn evaluate_args(
&self,
call: &Spanned<CallNode>,
registry: &dyn CommandRegistry,
scope: &Scope,
source: &Text,
) -> Result<Args, ShellError> {
let args = parse_command(self, registry, call, source)?;
trace!("parsed args: {:?}", args);
evaluate_args(args, registry, scope, source)
// let mut positional: Vec<Spanned<Value>> = vec![];
// let mut named: IndexMap<String, Value> = IndexMap::default();
// let mut args: Vec<TokenNode> = args.cloned().collect();
// for (key, ty) in self.named.iter() {
// let index = args.iter().position(|a| a.is_flag(&key, source));
// match (index, ty) {
// (Some(i), NamedType::Switch) => {
// args.remove(i);
// named.insert(key.clone(), Value::boolean(true));
// }
// (None, NamedType::Switch) => {}
// (Some(i), NamedType::Optional(v)) => {
// args.remove(i);
// named.insert(key.clone(), extract_named(&mut args, i, v)?);
// }
// (None, NamedType::Optional(_)) => {}
// (Some(i), NamedType::Mandatory(v)) => {
// args.remove(i);
// named.insert(key.clone(), extract_named(&mut args, i, v)?);
// }
// (None, NamedType::Mandatory(_)) => {
// return Err(ShellError::string(&format!(
// "Expected mandatory argument {}, but it was missing",
// key
// )))
// }
// }
// }
// let mut args = args.into_iter();
// for param in &self.mandatory_positional {
// let arg = args.next();
// let value = match arg {
// None => {
// return Err(ShellError::string(format!(
// "expected mandatory positional argument {}",
// param.name()
// )))
// }
// Some(arg) => param.evaluate(arg.clone(), scope, source)?,
// };
// positional.push(value);
// }
// if self.rest_positional {
// let rest: Result<Vec<Spanned<Value>>, _> = args
// .map(|i| evaluate_baseline_expr(&i, &Scope::empty(), source))
// .collect();
// positional.extend(rest?);
// } else {
// let rest: Vec<TokenNode> = args.collect();
// if rest.len() > 0 {
// return Err(ShellError::string(&format!(
// "Too many arguments, extras: {:?}",
// rest
// )));
// }
// }
// Ok(Args { positional, named })
}
#[allow(unused)]
crate fn signature(&self) -> String {
format!("TODO")
}
}
fn evaluate_args(
args: hir::Call,
registry: &dyn CommandRegistry,
scope: &Scope,
source: &Text,
) -> Result<Args, ShellError> {
let positional: Result<Option<Vec<_>>, _> = args
.positional()
.as_ref()
.map(|p| {
p.iter()
.map(|e| evaluate_baseline_expr(e, &(), scope, source))
.collect()
})
.transpose();
let positional = positional?;
let named: Result<Option<IndexMap<String, Spanned<Value>>>, ShellError> = args
.named()
.as_ref()
.map(|n| {
let mut results = IndexMap::new();
for (name, value) in n.named.iter() {
match value {
hir::named::NamedValue::PresentSwitch(span) => {
results.insert(
name.clone(),
Spanned::from_item(Value::boolean(true), *span),
);
}
hir::named::NamedValue::Value(expr) => {
results.insert(
name.clone(),
evaluate_baseline_expr(expr, registry, scope, source)?,
);
}
_ => {}
};
}
Ok(results)
})
.transpose();
let named = named?;
Ok(Args::new(positional, named))
}
pub trait CommandRegistry {
fn get(&self, name: &str) -> Option<CommandConfig>;
}
impl CommandRegistry for () {
fn get(&self, _name: &str) -> Option<CommandConfig> {
None
}
}