mirror of
https://github.com/nushell/nushell.git
synced 2025-08-10 03:38:07 +02:00
@ -1,4 +1,5 @@
|
||||
use derive_new::new;
|
||||
use getset::Getters;
|
||||
use std::str::FromStr;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
@ -40,25 +41,106 @@ impl FromStr for Operator {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub enum Expression {
|
||||
Leaf(Leaf),
|
||||
Binary(Binary),
|
||||
Parenthesized(Box<Parenthesized>),
|
||||
Block(Box<Block>),
|
||||
Binary(Box<Binary>),
|
||||
Path(Box<Path>),
|
||||
VariableReference(Variable),
|
||||
}
|
||||
|
||||
impl Expression {
|
||||
crate fn print(&self) -> String {
|
||||
match self {
|
||||
Expression::Leaf(l) => l.print(),
|
||||
Expression::Parenthesized(p) => p.print(),
|
||||
Expression::Block(b) => b.print(),
|
||||
Expression::VariableReference(r) => r.print(),
|
||||
Expression::Path(p) => p.print(),
|
||||
Expression::Binary(b) => b.print(),
|
||||
}
|
||||
}
|
||||
|
||||
crate fn as_string(&self) -> Option<String> {
|
||||
match self {
|
||||
Expression::Leaf(Leaf::String(s)) | Expression::Leaf(Leaf::Bare(s)) => {
|
||||
Some(s.to_string())
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, new)]
|
||||
pub struct Block {
|
||||
crate expr: Expression,
|
||||
}
|
||||
|
||||
impl Block {
|
||||
fn print(&self) -> String {
|
||||
format!("{{ {} }}", self.expr.print())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, new)]
|
||||
pub struct Parenthesized {
|
||||
crate expr: Expression,
|
||||
}
|
||||
|
||||
impl Parenthesized {
|
||||
fn print(&self) -> String {
|
||||
format!("({})", self.expr.print())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Getters, new)]
|
||||
pub struct Path {
|
||||
#[get = "crate"]
|
||||
head: Expression,
|
||||
|
||||
#[get = "crate"]
|
||||
tail: Vec<String>,
|
||||
}
|
||||
|
||||
impl Path {
|
||||
crate fn print(&self) -> String {
|
||||
let mut out = self.head.print();
|
||||
|
||||
for item in self.tail.iter() {
|
||||
out.push_str(&format!(".{}", item));
|
||||
}
|
||||
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub enum Variable {
|
||||
It,
|
||||
True,
|
||||
False,
|
||||
Other(String),
|
||||
}
|
||||
|
||||
impl Variable {
|
||||
fn print(&self) -> String {
|
||||
match self {
|
||||
Variable::It => format!("$it"),
|
||||
Variable::True => format!("$true"),
|
||||
Variable::False => format!("$false"),
|
||||
Variable::Other(s) => format!("${}", s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub enum Leaf {
|
||||
String(String),
|
||||
Bare(String),
|
||||
|
||||
#[allow(unused)]
|
||||
Boolean(bool),
|
||||
Int(i64),
|
||||
}
|
||||
@ -74,11 +156,11 @@ impl Leaf {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, new)]
|
||||
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, new)]
|
||||
pub struct Binary {
|
||||
crate left: Leaf,
|
||||
crate left: Expression,
|
||||
crate operator: Operator,
|
||||
crate right: Leaf,
|
||||
crate right: Expression,
|
||||
}
|
||||
|
||||
impl Binary {
|
@ -1,6 +1,6 @@
|
||||
use std::str::FromStr;
|
||||
use crate::parser::tokens::*;
|
||||
use byte_unit::Byte;
|
||||
use crate::parser::ast::*;
|
||||
|
||||
grammar;
|
||||
|
||||
@ -10,12 +10,59 @@ pub Pipeline: Pipeline = {
|
||||
}
|
||||
|
||||
Command: ParsedCommand = {
|
||||
<command:RawBareWord> <expr:Expr*> => ParsedCommand::new(command, expr)
|
||||
<command:RawBareWord> <expr:Expr*> => ParsedCommand::new(command, expr),
|
||||
<command:RawBareWord> <expr:BinaryExpression> => ParsedCommand::new(command, vec![expr]),
|
||||
}
|
||||
|
||||
Leaf: Expression = {
|
||||
<String> => Expression::Leaf(Leaf::String(<>)),
|
||||
<Num> => Expression::Leaf(Leaf::Int(<>)),
|
||||
<Variable> => Expression::VariableReference(<>),
|
||||
}
|
||||
|
||||
BinaryExpression: Expression = {
|
||||
<left:Expr> <op:Operator> <right:Leaf> => Expression::Binary(Box::new(Binary::new(left, op, right))),
|
||||
}
|
||||
|
||||
Parenthesized: Expression = {
|
||||
"(" <Leaf> ")" => Expression::Parenthesized(Box::new(Parenthesized::new(<>))),
|
||||
"(" <BinaryExpression> ")" => Expression::Parenthesized(Box::new(Parenthesized::new(<>))),
|
||||
}
|
||||
|
||||
AtomicExpression: Expression = {
|
||||
<Parenthesized>,
|
||||
<Leaf>,
|
||||
}
|
||||
|
||||
Block: Expression = {
|
||||
"{" <AtomicExpression> "}" => Expression::Block(Box::new(Block::new(<>))),
|
||||
"{" <BinaryExpression> "}" => Expression::Block(Box::new(Block::new(<>))),
|
||||
}
|
||||
|
||||
WholeExpression: Expression = {
|
||||
<AtomicExpression>,
|
||||
<Block>,
|
||||
}
|
||||
|
||||
PathExpression: Expression = {
|
||||
<head:WholeExpression> <tail: ( "." <Member> )*> => Expression::Path(Box::new(Path::new(head, tail)))
|
||||
}
|
||||
|
||||
Expr: Expression = {
|
||||
<Leaf> => Expression::Leaf(<>),
|
||||
<Binary> => Expression::Binary(<>),
|
||||
<RawBareWord> => Expression::Leaf(Leaf::Bare(<>)),
|
||||
<PathExpression>
|
||||
}
|
||||
|
||||
Variable: Variable = {
|
||||
"$true" => Variable::True,
|
||||
"$false" => Variable::False,
|
||||
"$it" => Variable::It,
|
||||
"$" <RawBareWord> => Variable::Other(<>.to_string()),
|
||||
}
|
||||
|
||||
Member: String = {
|
||||
<RawBareWord>,
|
||||
<String>
|
||||
}
|
||||
|
||||
Operator: Operator = {
|
||||
@ -27,10 +74,6 @@ Operator: Operator = {
|
||||
">=" => Operator::GreaterThanOrEqual
|
||||
}
|
||||
|
||||
Binary: Binary = {
|
||||
<left:Leaf> <op:Operator> <right:Leaf> => Binary::new(left, op, right),
|
||||
}
|
||||
|
||||
Flag: Flag = {
|
||||
"-" <RawBareWord> => Flag::Shorthand(<>.to_string()),
|
||||
"--" <RawBareWord> => Flag::Longhand(<>.to_string()),
|
||||
@ -41,18 +84,7 @@ String: String = {
|
||||
DQString,
|
||||
}
|
||||
|
||||
Leaf: Leaf = {
|
||||
<String> => Leaf::String(<>),
|
||||
<Size> => Leaf::Int(<>),
|
||||
<Num> => Leaf::Int(<>),
|
||||
<RawBareWord> => match <>.as_ref() {
|
||||
"true" => Leaf::Boolean(true),
|
||||
"false" => Leaf::Boolean(false),
|
||||
_ => Leaf::Bare(<>),
|
||||
}
|
||||
}
|
||||
|
||||
RawBareWord: String = <s:r#"[^0-9"'\-][^\s]*"#> => <>.to_string();
|
||||
RawBareWord: String = <s:r#"[^0-9"'\-][^\s"']*"#> => <>.to_string();
|
||||
DQString: String = <s:r#""([^"]|\\")*""#> => s[1..s.len() - 1].to_string();
|
||||
SQString: String = <s:r#"'([^']|\\')*'"#> => s[1..s.len() - 1].to_string();
|
||||
Num: i64 = <s:r"-?[0-9]+"> => i64::from_str(s).unwrap();
|
||||
|
2146
src/parser/parser.rs
2146
src/parser/parser.rs
File diff suppressed because it is too large
Load Diff
@ -1,19 +1,110 @@
|
||||
use crate::evaluate::{evaluate_expr, Scope};
|
||||
use crate::prelude::*;
|
||||
use indexmap::IndexMap;
|
||||
|
||||
#[allow(unused)]
|
||||
pub enum CommandType {
|
||||
Switch,
|
||||
Single,
|
||||
Array,
|
||||
#[derive(Debug)]
|
||||
pub enum NamedType {
|
||||
Switch(String),
|
||||
Single(String),
|
||||
Array(String),
|
||||
Block(String),
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PositionalType {
|
||||
Value(String),
|
||||
Block(String),
|
||||
}
|
||||
|
||||
impl PositionalType {
|
||||
crate fn name(&self) -> String {
|
||||
match self {
|
||||
PositionalType::Value(s) => s.clone(),
|
||||
PositionalType::Block(s) => s.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
crate fn evaluate(&self, arg: ast::Expression, scope: &Scope) -> Result<Value, ShellError> {
|
||||
match self {
|
||||
PositionalType::Value(_) => evaluate_expr(&arg, scope),
|
||||
PositionalType::Block(_) => match arg {
|
||||
ast::Expression::Block(b) => Ok(Value::block(b.expr)),
|
||||
ast::Expression::Binary(b) => {
|
||||
if let Some(s) = b.left.as_string() {
|
||||
Ok(Value::block(ast::Expression::Binary(Box::new(
|
||||
ast::Binary::new(
|
||||
ast::Expression::Path(Box::new(ast::Path::new(
|
||||
ast::Expression::VariableReference(ast::Variable::It),
|
||||
vec![s],
|
||||
))),
|
||||
b.operator,
|
||||
b.right,
|
||||
),
|
||||
))))
|
||||
} else {
|
||||
Ok(Value::block(ast::Expression::Binary(b)))
|
||||
}
|
||||
}
|
||||
other => Ok(Value::block(other)), // other =>
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CommandConfig {
|
||||
crate name: String,
|
||||
crate mandatory_positional: Vec<String>,
|
||||
crate optional_positional: Vec<String>,
|
||||
crate mandatory_positional: Vec<PositionalType>,
|
||||
crate optional_positional: Vec<PositionalType>,
|
||||
crate rest_positional: bool,
|
||||
crate named: IndexMap<String, CommandType>,
|
||||
crate named: IndexMap<String, NamedType>,
|
||||
}
|
||||
|
||||
impl CommandConfig {
|
||||
crate fn evaluate_args(
|
||||
&self,
|
||||
mut args: impl Iterator<Item = &'expr ast::Expression>,
|
||||
scope: &Scope,
|
||||
) -> Result<Vec<Value>, ShellError> {
|
||||
let mut results: Vec<Value> = vec![];
|
||||
|
||||
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)?,
|
||||
};
|
||||
|
||||
results.push(value);
|
||||
}
|
||||
|
||||
if self.rest_positional {
|
||||
let rest: Result<Vec<Value>, _> =
|
||||
args.map(|i| evaluate_expr(i, &Scope::empty())).collect();
|
||||
results.extend(rest?);
|
||||
} else {
|
||||
match args.next() {
|
||||
None => {}
|
||||
Some(_) => return Err(ShellError::string("Too many arguments")),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
crate fn signature(&self) -> String {
|
||||
format!("TODO")
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CommandRegistry {
|
||||
|
Reference in New Issue
Block a user