Improve signature infrastructure

The `config` command uses different kinds of named arguments, which
illustrates how it works.
This commit is contained in:
Yehuda Katz
2019-05-31 22:50:16 -07:00
parent 9df8a261ab
commit 69effbc9e7
36 changed files with 673 additions and 208 deletions

View File

@ -85,6 +85,13 @@ impl Expression {
_ => None,
}
}
crate fn is_flag(&self, value: &str) -> bool {
match self {
Expression::Flag(Flag::Longhand(f)) if value == f => true,
_ => false,
}
}
}
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, new)]
@ -151,17 +158,22 @@ impl Path {
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub enum Variable {
It,
True,
False,
Other(String),
}
impl Variable {
crate fn from_str(input: &str) -> Expression {
match input {
"it" => Expression::VariableReference(Variable::It),
"true" => Expression::Leaf(Leaf::Boolean(true)),
"false" => Expression::Leaf(Leaf::Boolean(false)),
other => Expression::VariableReference(Variable::Other(other.to_string())),
}
}
fn print(&self) -> String {
match self {
Variable::It => format!("$it"),
Variable::True => format!("$true"),
Variable::False => format!("$false"),
Variable::Other(s) => format!("${}", s),
}
}
@ -171,18 +183,6 @@ impl Variable {
}
}
impl FromStr for Variable {
type Err = ();
fn from_str(input: &str) -> Result<Self, <Self as std::str::FromStr>::Err> {
Ok(match input {
"it" => Variable::It,
"true" => Variable::True,
"false" => Variable::False,
other => Variable::Other(other.to_string()),
})
}
}
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct BarePath {
head: String,

View File

@ -65,8 +65,8 @@ Expr: Expression = {
<PathHead>
}
Variable: Variable = {
"$" <"variable"> => Variable::from_str(<>.as_slice()).unwrap(),
Variable: Expression = {
"$" <"variable"> => Variable::from_str(<>.as_slice()),
}
Member: String = {

View File

@ -1,5 +1,5 @@
// auto-generated: "lalrpop 0.17.0"
// sha256: efaf89a1d956869b47a3f5daff048341c19934c68ad5e1ed9fe8e5c4222d2
// sha256: 327a2eaaded6615e365add5d44719ae0dd3217f5b0fc3ba130f052328c2bd439
#![allow(unused)]
use std::str::FromStr;
use crate::parser::ast::*;
@ -41,7 +41,6 @@ mod __parse__Pipeline {
Variant10(i64),
Variant11(Operator),
Variant12(Pipeline),
Variant13(Variable),
}
const __ACTION: &'static [i8] = &[
// State 0
@ -1364,17 +1363,6 @@ mod __parse__Pipeline {
_ => panic!("symbol type mismatch")
}
}
fn __pop_Variant13<
'input,
>(
__symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>
) -> (usize, Variable, usize)
{
match __symbols.pop().unwrap() {
(__l, __Symbol::Variant13(__v), __r) => (__l, __v, __r),
_ => panic!("symbol type mismatch")
}
}
fn __pop_Variant10<
'input,
>(
@ -2022,7 +2010,7 @@ mod __parse__Pipeline {
) -> (usize, usize)
{
// Leaf = Variable => ActionFn(9);
let __sym0 = __pop_Variant13(__symbols);
let __sym0 = __pop_Variant6(__symbols);
let __start = __sym0.0.clone();
let __end = __sym0.2.clone();
let __nt = super::__action9::<>(__sym0);
@ -2393,7 +2381,7 @@ mod __parse__Pipeline {
let __start = __sym0.0.clone();
let __end = __sym1.2.clone();
let __nt = super::__action25::<>(__sym0, __sym1);
__symbols.push((__start, __Symbol::Variant13(__nt), __end));
__symbols.push((__start, __Symbol::Variant6(__nt), __end));
(2, 25)
}
pub(crate) fn __reduce52<
@ -2522,7 +2510,7 @@ fn __action8<
fn __action9<
'input,
>(
(_, __0, _): (usize, Variable, usize),
(_, __0, _): (usize, Expression, usize),
) -> Expression
{
Expression::VariableReference(__0)
@ -2679,9 +2667,9 @@ fn __action25<
>(
(_, _, _): (usize, SpannedToken<'input>, usize),
(_, __0, _): (usize, SpannedToken<'input>, usize),
) -> Variable
) -> Expression
{
Variable::from_str(__0.as_slice()).unwrap()
Variable::from_str(__0.as_slice())
}
fn __action26<

View File

@ -5,10 +5,21 @@ use indexmap::IndexMap;
#[allow(unused)]
#[derive(Debug)]
pub enum NamedType {
Switch(String),
Single(String),
Array(String),
Block(String),
Switch,
Mandatory(NamedValue),
Optional(NamedValue),
}
#[derive(Debug)]
pub enum NamedValue {
Single,
Tuple,
#[allow(unused)]
Block,
#[allow(unused)]
Array,
}
#[allow(unused)]
@ -62,13 +73,55 @@ pub struct CommandConfig {
crate named: IndexMap<String, NamedType>,
}
pub struct Args {
pub positional: Vec<Value>,
pub named: IndexMap<String, Value>,
}
impl CommandConfig {
crate fn evaluate_args(
&self,
mut args: impl Iterator<Item = &'expr ast::Expression>,
args: impl Iterator<Item = &'expr ast::Expression>,
scope: &Scope,
) -> Result<Vec<Value>, ShellError> {
let mut results: Vec<Value> = vec![];
) -> Result<Args, ShellError> {
let mut positional: Vec<Value> = vec![];
let mut named: IndexMap<String, Value> = IndexMap::default();
let mut args: Vec<ast::Expression> = args.cloned().collect();
for (key, ty) in self.named.iter() {
let index = args.iter().position(|a| a.is_flag(&key));
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();
@ -84,21 +137,25 @@ impl CommandConfig {
Some(arg) => param.evaluate(arg.clone(), scope)?,
};
results.push(value);
positional.push(value);
}
if self.rest_positional {
let rest: Result<Vec<Value>, _> =
args.map(|i| evaluate_expr(i, &Scope::empty())).collect();
results.extend(rest?);
args.map(|i| evaluate_expr(&i, &Scope::empty())).collect();
positional.extend(rest?);
} else {
match args.next() {
None => {}
Some(_) => return Err(ShellError::string("Too many arguments")),
let rest: Vec<ast::Expression> = args.collect();
if rest.len() > 0 {
return Err(ShellError::string(&format!(
"Too many arguments, extras: {:?}",
rest
)));
}
}
Ok(results)
Ok(Args { positional, named })
}
#[allow(unused)]
@ -107,6 +164,49 @@ impl CommandConfig {
}
}
fn extract_named(
v: &mut Vec<ast::Expression>,
position: usize,
ty: &NamedValue,
) -> Result<Value, ShellError> {
match ty {
NamedValue::Single => {
let expr = v.remove(position);
expect_simple_expr(expr)
}
NamedValue::Tuple => {
let expr = v.remove(position);
let next = v.remove(position);
let list = vec![expect_simple_expr(expr)?, expect_simple_expr(next)?];
Ok(Value::List(list))
}
other => Err(ShellError::string(&format!(
"Unimplemented named argument {:?}",
other
))),
}
}
fn expect_simple_expr(expr: ast::Expression) -> Result<Value, ShellError> {
match expr {
ast::Expression::Leaf(l) => Ok(match l {
ast::Leaf::Bare(s) => Value::string(s.to_string()),
ast::Leaf::String(s) => Value::string(s),
ast::Leaf::Boolean(b) => Value::boolean(b),
ast::Leaf::Int(i) => Value::int(i),
}),
// TODO: Diagnostic
other => Err(ShellError::string(&format!(
"Expected a value, found {}",
other.print()
))),
}
}
pub trait CommandRegistry {
fn get(&self, name: &str) -> CommandConfig;
}