Add nu-protocol

This commit is contained in:
JT 2021-09-02 13:29:43 +12:00
parent c4c4d82bf4
commit 3d252a9797
35 changed files with 296 additions and 247 deletions

11
Cargo.lock generated
View file

@ -292,14 +292,20 @@ dependencies = [
"nu-ansi-term", "nu-ansi-term",
"nu-engine", "nu-engine",
"nu-parser", "nu-parser",
"nu-protocol",
"reedline", "reedline",
] ]
[[package]]
name = "nu-command"
version = "0.1.0"
[[package]] [[package]]
name = "nu-engine" name = "nu-engine"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"nu-parser", "nu-parser",
"nu-protocol",
] ]
[[package]] [[package]]
@ -320,8 +326,13 @@ name = "nu-parser"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"codespan-reporting", "codespan-reporting",
"nu-protocol",
] ]
[[package]]
name = "nu-protocol"
version = "0.1.0"
[[package]] [[package]]
name = "num-integer" name = "num-integer"
version = "0.1.44" version = "0.1.44"

View file

@ -6,7 +6,7 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[workspace] [workspace]
members = ["crates/nu-cli", "crates/nu-engine", "crates/nu-parser"] members = ["crates/nu-cli", "crates/nu-engine", "crates/nu-parser", "crates/nu-command", "crates/nu-protocol"]
[dependencies] [dependencies]
reedline = { git = "https://github.com/jntrnr/reedline", branch = "main" } reedline = { git = "https://github.com/jntrnr/reedline", branch = "main" }

View file

@ -6,6 +6,7 @@ edition = "2018"
[dependencies] [dependencies]
nu-engine = { path = "../nu-engine" } nu-engine = { path = "../nu-engine" }
nu-parser = { path = "../nu-parser" } nu-parser = { path = "../nu-parser" }
nu-protocol = { path = "../nu-protocol" }
codespan-reporting = "0.11.1" codespan-reporting = "0.11.1"
nu-ansi-term = "0.32.0" nu-ansi-term = "0.32.0"
reedline = { git = "https://github.com/jntrnr/reedline", branch = "main" } reedline = { git = "https://github.com/jntrnr/reedline", branch = "main" }

View file

@ -1,6 +1,7 @@
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
use nu_parser::{ParserState, ParserWorkingSet, Signature, SyntaxShape}; use nu_parser::{ParserState, ParserWorkingSet};
use nu_protocol::{Signature, SyntaxShape};
pub fn create_default_context() -> Rc<RefCell<ParserState>> { pub fn create_default_context() -> Rc<RefCell<ParserState>> {
let parser_state = Rc::new(RefCell::new(ParserState::new())); let parser_state = Rc::new(RefCell::new(ParserState::new()));

View file

@ -2,8 +2,8 @@ use core::ops::Range;
use codespan_reporting::diagnostic::{Diagnostic, Label}; use codespan_reporting::diagnostic::{Diagnostic, Label};
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
use nu_engine::ShellError; use nu_parser::{ParseError, ParserWorkingSet};
use nu_parser::{ParseError, ParserWorkingSet, Span}; use nu_protocol::{ShellError, Span};
fn convert_span_to_diag( fn convert_span_to_diag(
working_set: &ParserWorkingSet, working_set: &ParserWorkingSet,

View file

@ -0,0 +1,8 @@
[package]
name = "nu-command"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

View file

@ -0,0 +1,7 @@
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}

View file

@ -5,3 +5,4 @@ edition = "2018"
[dependencies] [dependencies]
nu-parser = { path = "../nu-parser" } nu-parser = { path = "../nu-parser" }
nu-protocol = { path = "../nu-protocol" }

View file

@ -1,26 +1,8 @@
use std::time::Instant; use std::time::Instant;
use crate::{ use crate::state::State;
state::State, use nu_parser::{Block, Call, Expr, Expression, Operator, Statement};
value::{IntoRowStream, IntoValueStream, Value}, use nu_protocol::{IntoRowStream, IntoValueStream, ShellError, Span, Value};
};
use nu_parser::{Block, Call, Expr, Expression, Operator, Span, Statement, Type};
#[derive(Debug)]
pub enum ShellError {
OperatorMismatch {
op_span: Span,
lhs_ty: Type,
lhs_span: Span,
rhs_ty: Type,
rhs_span: Span,
},
Unsupported(Span),
InternalError(String),
VariableNotFound(Span),
CantConvert(String, Span),
DivisionByZero(Span),
}
pub fn eval_operator(op: &Expression) -> Result<Operator, ShellError> { pub fn eval_operator(op: &Expression) -> Result<Operator, ShellError> {
match op { match op {

View file

@ -1,7 +1,5 @@
mod eval; mod eval;
mod state; mod state;
mod value;
pub use eval::{eval_block, eval_expression, eval_operator, ShellError}; pub use eval::{eval_block, eval_expression, eval_operator};
pub use state::{Stack, State}; pub use state::{Stack, State};
pub use value::Value;

View file

@ -1,7 +1,7 @@
use nu_parser::{ParserState, VarId}; use nu_parser::ParserState;
use std::{cell::RefCell, collections::HashMap, rc::Rc}; use std::{cell::RefCell, collections::HashMap, rc::Rc};
use crate::{value::Value, ShellError}; use nu_protocol::{ShellError, Value, VarId};
pub struct State { pub struct State {
pub parser_state: Rc<RefCell<ParserState>>, pub parser_state: Rc<RefCell<ParserState>>,

View file

@ -5,3 +5,4 @@ edition = "2018"
[dependencies] [dependencies]
codespan-reporting = "0.11.1" codespan-reporting = "0.11.1"
nu-protocol = { path = "../nu-protocol"}

View file

@ -1,9 +1,7 @@
use crate::parser_state::Type;
use crate::ParserWorkingSet; use crate::ParserWorkingSet;
use nu_protocol::{Span, Type};
use std::ops::Range; use std::ops::Range;
pub use crate::Span;
#[derive(Debug)] #[derive(Debug)]
pub enum ParseError { pub enum ParseError {
ExtraTokens(Span), ExtraTokens(Span),

View file

@ -1,4 +1,5 @@
use crate::{Block, Expr, Expression, ParserWorkingSet, Pipeline, Span, Statement}; use crate::{Block, Expr, Expression, ParserWorkingSet, Pipeline, Statement};
use nu_protocol::Span;
#[derive(Debug)] #[derive(Debug)]
pub enum FlatShape { pub enum FlatShape {

View file

@ -1,4 +1,5 @@
use crate::{ParseError, Span}; use crate::ParseError;
use nu_protocol::Span;
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub enum TokenContents { pub enum TokenContents {

View file

@ -1,23 +1,14 @@
mod declaration;
mod errors; mod errors;
mod flatten; mod flatten;
mod lex; mod lex;
mod lite_parse; mod lite_parse;
mod parser; mod parser;
mod parser_state; mod parser_state;
mod signature;
mod span;
mod type_check; mod type_check;
pub use declaration::Declaration;
pub use errors::ParseError; pub use errors::ParseError;
pub use flatten::FlatShape; pub use flatten::FlatShape;
pub use lex::{lex, Token, TokenContents}; pub use lex::{lex, Token, TokenContents};
pub use lite_parse::{lite_parse, LiteBlock}; pub use lite_parse::{lite_parse, LiteBlock};
pub use parser::{ pub use parser::{Block, Call, Expr, Expression, Import, Operator, Pipeline, Statement, VarDecl};
span, Block, Call, Expr, Expression, Import, Operator, Pipeline, Statement, SyntaxShape, pub use parser_state::{ParserDelta, ParserState, ParserWorkingSet};
VarDecl,
};
pub use parser_state::{BlockId, DeclId, ParserDelta, ParserState, ParserWorkingSet, Type, VarId};
pub use signature::{Flag, PositionalArg, Signature};
pub use span::Span;

View file

@ -1,4 +1,5 @@
use crate::{ParseError, Span, Token, TokenContents}; use crate::{ParseError, Token, TokenContents};
use nu_protocol::Span;
#[derive(Debug)] #[derive(Debug)]
pub struct LiteCommand { pub struct LiteCommand {

View file

@ -3,117 +3,13 @@ use std::{
ops::{Index, IndexMut}, ops::{Index, IndexMut},
}; };
use crate::{ use crate::{lex, lite_parse, LiteBlock, ParseError, ParserWorkingSet, Token, TokenContents};
lex, lite_parse,
parser_state::{Type, VarId}, use nu_protocol::{
signature::{Flag, PositionalArg}, span, BlockId, DeclId, Declaration, Flag, PositionalArg, Signature, Span, SyntaxShape, Type,
BlockId, DeclId, Declaration, LiteBlock, ParseError, ParserWorkingSet, Signature, Span, Token, VarId,
TokenContents,
}; };
/// The syntactic shapes that values must match to be passed into a command. You can think of this as the type-checking that occurs when you call a function.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SyntaxShape {
/// A specific match to a word or symbol
Keyword(Vec<u8>, Box<SyntaxShape>),
/// Any syntactic form is allowed
Any,
/// Strings and string-like bare words are allowed
String,
/// A dotted path to navigate the table
ColumnPath,
/// A dotted path to navigate the table (including variable)
FullColumnPath,
/// Only a numeric (integer or decimal) value is allowed
Number,
/// A range is allowed (eg, `1..3`)
Range,
/// Only an integer value is allowed
Int,
/// A filepath is allowed
FilePath,
/// A glob pattern is allowed, eg `foo*`
GlobPattern,
/// A block is allowed, eg `{start this thing}`
Block,
/// A table is allowed, eg `[[first, second]; [1, 2]]`
Table,
/// A table is allowed, eg `[first second]`
List(Box<SyntaxShape>),
/// A filesize value is allowed, eg `10kb`
Filesize,
/// A duration value is allowed, eg `19day`
Duration,
/// An operator
Operator,
/// A math expression which expands shorthand forms on the lefthand side, eg `foo > 1`
/// The shorthand allows us to more easily reach columns inside of the row being passed in
RowCondition,
/// A general math expression, eg `1 + 2`
MathExpression,
/// A variable name
Variable,
/// A variable with optional type, `x` or `x: int`
VarWithOptType,
/// A signature for a definition, `[x:int, --foo]`
Signature,
/// A general expression, eg `1 + 2` or `foo --bar`
Expression,
}
impl SyntaxShape {
pub fn to_type(&self) -> Type {
match self {
SyntaxShape::Any => Type::Unknown,
SyntaxShape::Block => Type::Block,
SyntaxShape::ColumnPath => Type::Unknown,
SyntaxShape::Duration => Type::Duration,
SyntaxShape::Expression => Type::Unknown,
SyntaxShape::FilePath => Type::FilePath,
SyntaxShape::Filesize => Type::Filesize,
SyntaxShape::FullColumnPath => Type::Unknown,
SyntaxShape::GlobPattern => Type::String,
SyntaxShape::Int => Type::Int,
SyntaxShape::List(x) => {
let contents = x.to_type();
Type::List(Box::new(contents))
}
SyntaxShape::Keyword(_, expr) => expr.to_type(),
SyntaxShape::MathExpression => Type::Unknown,
SyntaxShape::Number => Type::Number,
SyntaxShape::Operator => Type::Unknown,
SyntaxShape::Range => Type::Unknown,
SyntaxShape::RowCondition => Type::Bool,
SyntaxShape::Signature => Type::Unknown,
SyntaxShape::String => Type::String,
SyntaxShape::Table => Type::Table,
SyntaxShape::VarWithOptType => Type::Unknown,
SyntaxShape::Variable => Type::Unknown,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum Operator { pub enum Operator {
Equal, Equal,
@ -404,21 +300,6 @@ fn check_call(command: Span, sig: &Signature, call: &Call) -> Option<ParseError>
} }
} }
pub fn span(spans: &[Span]) -> Span {
let length = spans.len();
if length == 0 {
Span::unknown()
} else if length == 1 {
spans[0]
} else {
Span {
start: spans[0].start,
end: spans[length - 1].end,
}
}
}
impl<'a> ParserWorkingSet<'a> { impl<'a> ParserWorkingSet<'a> {
pub fn parse_external_call(&mut self, spans: &[Span]) -> (Expression, Option<ParseError>) { pub fn parse_external_call(&mut self, spans: &[Span]) -> (Expression, Option<ParseError>) {
// TODO: add external parsing // TODO: add external parsing
@ -725,7 +606,7 @@ impl<'a> ParserWorkingSet<'a> {
call.decl_id = decl_id; call.decl_id = decl_id;
call.head = command_span; call.head = command_span;
let decl = self.get_decl(decl_id).clone(); let signature = self.get_decl(decl_id).signature.clone();
// The index into the positional parameter in the definition // The index into the positional parameter in the definition
let mut positional_idx = 0; let mut positional_idx = 0;
@ -738,8 +619,7 @@ impl<'a> ParserWorkingSet<'a> {
let arg_span = spans[spans_idx]; let arg_span = spans[spans_idx];
// Check if we're on a long flag, if so, parse // Check if we're on a long flag, if so, parse
let (long_name, arg, err) = let (long_name, arg, err) = self.parse_long_flag(spans, &mut spans_idx, &signature);
self.parse_long_flag(spans, &mut spans_idx, &decl.signature);
if let Some(long_name) = long_name { if let Some(long_name) = long_name {
// We found a long flag, like --bar // We found a long flag, like --bar
error = error.or(err); error = error.or(err);
@ -750,7 +630,7 @@ impl<'a> ParserWorkingSet<'a> {
// Check if we're on a short flag or group of short flags, if so, parse // Check if we're on a short flag or group of short flags, if so, parse
let (short_flags, err) = let (short_flags, err) =
self.parse_short_flags(spans, &mut spans_idx, positional_idx, &decl.signature); self.parse_short_flags(spans, &mut spans_idx, positional_idx, &signature);
if let Some(short_flags) = short_flags { if let Some(short_flags) = short_flags {
error = error.or(err); error = error.or(err);
@ -774,8 +654,9 @@ impl<'a> ParserWorkingSet<'a> {
} }
// Parse a positional arg if there is one // Parse a positional arg if there is one
if let Some(positional) = decl.signature.get_positional(positional_idx) { if let Some(positional) = signature.get_positional(positional_idx) {
//Make sure we leave enough spans for the remaining positionals //Make sure we leave enough spans for the remaining positionals
let decl = self.get_decl(decl_id);
let end = self.calculate_end_span(&decl, spans, spans_idx, positional_idx); let end = self.calculate_end_span(&decl, spans, spans_idx, positional_idx);
@ -813,7 +694,7 @@ impl<'a> ParserWorkingSet<'a> {
spans_idx += 1; spans_idx += 1;
} }
let err = check_call(command_span, &decl.signature, &call); let err = check_call(command_span, &signature, &call);
error = error.or(err); error = error.or(err);
// FIXME: type unknown // FIXME: type unknown

View file

@ -1,8 +1,8 @@
use crate::{parser::Block, Declaration, Span}; use crate::parser::Block;
use core::panic; use core::panic;
use std::{collections::HashMap, fmt::Display, slice::Iter}; use nu_protocol::{BlockId, DeclId, Declaration, Span, Type, VarId};
use std::{collections::HashMap, slice::Iter};
#[derive(Debug)]
pub struct ParserState { pub struct ParserState {
files: Vec<(String, usize, usize)>, files: Vec<(String, usize, usize)>,
file_contents: Vec<u8>, file_contents: Vec<u8>,
@ -12,49 +12,6 @@ pub struct ParserState {
scope: Vec<ScopeFrame>, scope: Vec<ScopeFrame>,
} }
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Type {
Int,
Float,
Bool,
String,
Block,
ColumnPath,
Duration,
FilePath,
Filesize,
List(Box<Type>),
Number,
Nothing,
Table,
Unknown,
}
impl Display for Type {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Type::Block => write!(f, "block"),
Type::Bool => write!(f, "bool"),
Type::ColumnPath => write!(f, "column path"),
Type::Duration => write!(f, "duration"),
Type::FilePath => write!(f, "filepath"),
Type::Filesize => write!(f, "filesize"),
Type::Float => write!(f, "float"),
Type::Int => write!(f, "int"),
Type::List(l) => write!(f, "list<{}>", l),
Type::Nothing => write!(f, "nothing"),
Type::Number => write!(f, "number"),
Type::String => write!(f, "string"),
Type::Table => write!(f, "table"),
Type::Unknown => write!(f, "unknown"),
}
}
}
pub type VarId = usize;
pub type DeclId = usize;
pub type BlockId = usize;
#[derive(Debug)] #[derive(Debug)]
struct ScopeFrame { struct ScopeFrame {
vars: HashMap<Vec<u8>, VarId>, vars: HashMap<Vec<u8>, VarId>,
@ -136,7 +93,7 @@ impl ParserState {
pub fn print_decls(&self) { pub fn print_decls(&self) {
for decl in self.decls.iter().enumerate() { for decl in self.decls.iter().enumerate() {
println!("decl{}: {:?}", decl.0, decl.1); println!("decl{}: {:?}", decl.0, decl.1.signature);
} }
} }
@ -219,13 +176,11 @@ impl ParserState {
} }
} }
#[derive(Debug)]
pub struct ParserWorkingSet<'a> { pub struct ParserWorkingSet<'a> {
permanent_state: &'a ParserState, permanent_state: &'a ParserState,
pub delta: ParserDelta, pub delta: ParserDelta,
} }
#[derive(Debug)]
pub struct ParserDelta { pub struct ParserDelta {
files: Vec<(String, usize, usize)>, files: Vec<(String, usize, usize)>,
pub(crate) file_contents: Vec<u8>, pub(crate) file_contents: Vec<u8>,

View file

@ -1,4 +1,5 @@
use crate::{parser::Operator, parser_state::Type, Expr, Expression, ParseError, ParserWorkingSet}; use crate::{parser::Operator, Expr, Expression, ParseError, ParserWorkingSet};
use nu_protocol::Type;
impl<'a> ParserWorkingSet<'a> { impl<'a> ParserWorkingSet<'a> {
pub fn type_compatible(lhs: &Type, rhs: &Type) -> bool { pub fn type_compatible(lhs: &Type, rhs: &Type) -> bool {

View file

@ -1,4 +1,5 @@
use nu_parser::{lex, ParseError, Span, Token, TokenContents}; use nu_parser::{lex, ParseError, Token, TokenContents};
use nu_protocol::Span;
#[test] #[test]
fn lex_basic() { fn lex_basic() {

View file

@ -1,4 +1,5 @@
use nu_parser::{lex, lite_parse, LiteBlock, ParseError, Span}; use nu_parser::{lex, lite_parse, LiteBlock, ParseError};
use nu_protocol::Span;
fn lite_parse_helper(input: &[u8]) -> Result<LiteBlock, ParseError> { fn lite_parse_helper(input: &[u8]) -> Result<LiteBlock, ParseError> {
let (output, err) = lex(input, 0, &[], &[]); let (output, err) = lex(input, 0, &[], &[]);

View file

@ -1,5 +1,6 @@
use nu_parser::*; use nu_parser::*;
use nu_parser::{ParseError, ParserState, Signature}; use nu_parser::{ParseError, ParserState};
use nu_protocol::{Signature, SyntaxShape};
#[test] #[test]
pub fn parse_int() { pub fn parse_int() {

View file

@ -0,0 +1,8 @@
[package]
name = "nu-protocol"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -0,0 +1,3 @@
# nu-protocol
The nu-protocol crate holds the definitions of structs/traits that are used throughout Nushell. This gives us one way to expose them to many other crates, as well as make these definitions available to each other, without causing mutually recursive dependencies.

View file

@ -1,6 +1,5 @@
use crate::{BlockId, Signature}; use crate::{BlockId, Signature};
#[derive(Clone, Debug)]
pub struct Declaration { pub struct Declaration {
pub signature: Box<Signature>, pub signature: Box<Signature>,
pub body: Option<BlockId>, pub body: Option<BlockId>,

View file

@ -0,0 +1,3 @@
pub type VarId = usize;
pub type DeclId = usize;
pub type BlockId = usize;

View file

@ -0,0 +1,17 @@
mod declaration;
mod id;
mod shell_error;
mod signature;
mod span;
mod syntax_shape;
mod ty;
mod value;
pub use declaration::*;
pub use id::*;
pub use shell_error::*;
pub use signature::*;
pub use span::*;
pub use syntax_shape::*;
pub use ty::*;
pub use value::*;

View file

@ -0,0 +1,17 @@
use crate::{Span, Type};
#[derive(Debug)]
pub enum ShellError {
OperatorMismatch {
op_span: Span,
lhs_ty: Type,
lhs_span: Span,
rhs_ty: Type,
rhs_span: Span,
},
Unsupported(Span),
InternalError(String),
VariableNotFound(Span),
CantConvert(String, Span),
DivisionByZero(Span),
}

View file

@ -1,4 +1,5 @@
use crate::{parser::SyntaxShape, Declaration, VarId}; use crate::VarId;
use crate::{Declaration, SyntaxShape};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Flag { pub struct Flag {

View file

@ -20,3 +20,18 @@ impl Span {
} }
} }
} }
pub fn span(spans: &[Span]) -> Span {
let length = spans.len();
if length == 0 {
Span::unknown()
} else if length == 1 {
spans[0]
} else {
Span {
start: spans[0].start,
end: spans[length - 1].end,
}
}
}

View file

@ -0,0 +1,104 @@
use crate::Type;
/// The syntactic shapes that values must match to be passed into a command. You can think of this as the type-checking that occurs when you call a function.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SyntaxShape {
/// A specific match to a word or symbol
Keyword(Vec<u8>, Box<SyntaxShape>),
/// Any syntactic form is allowed
Any,
/// Strings and string-like bare words are allowed
String,
/// A dotted path to navigate the table
ColumnPath,
/// A dotted path to navigate the table (including variable)
FullColumnPath,
/// Only a numeric (integer or decimal) value is allowed
Number,
/// A range is allowed (eg, `1..3`)
Range,
/// Only an integer value is allowed
Int,
/// A filepath is allowed
FilePath,
/// A glob pattern is allowed, eg `foo*`
GlobPattern,
/// A block is allowed, eg `{start this thing}`
Block,
/// A table is allowed, eg `[[first, second]; [1, 2]]`
Table,
/// A table is allowed, eg `[first second]`
List(Box<SyntaxShape>),
/// A filesize value is allowed, eg `10kb`
Filesize,
/// A duration value is allowed, eg `19day`
Duration,
/// An operator
Operator,
/// A math expression which expands shorthand forms on the lefthand side, eg `foo > 1`
/// The shorthand allows us to more easily reach columns inside of the row being passed in
RowCondition,
/// A general math expression, eg `1 + 2`
MathExpression,
/// A variable name
Variable,
/// A variable with optional type, `x` or `x: int`
VarWithOptType,
/// A signature for a definition, `[x:int, --foo]`
Signature,
/// A general expression, eg `1 + 2` or `foo --bar`
Expression,
}
impl SyntaxShape {
pub fn to_type(&self) -> Type {
match self {
SyntaxShape::Any => Type::Unknown,
SyntaxShape::Block => Type::Block,
SyntaxShape::ColumnPath => Type::Unknown,
SyntaxShape::Duration => Type::Duration,
SyntaxShape::Expression => Type::Unknown,
SyntaxShape::FilePath => Type::FilePath,
SyntaxShape::Filesize => Type::Filesize,
SyntaxShape::FullColumnPath => Type::Unknown,
SyntaxShape::GlobPattern => Type::String,
SyntaxShape::Int => Type::Int,
SyntaxShape::List(x) => {
let contents = x.to_type();
Type::List(Box::new(contents))
}
SyntaxShape::Keyword(_, expr) => expr.to_type(),
SyntaxShape::MathExpression => Type::Unknown,
SyntaxShape::Number => Type::Number,
SyntaxShape::Operator => Type::Unknown,
SyntaxShape::Range => Type::Unknown,
SyntaxShape::RowCondition => Type::Bool,
SyntaxShape::Signature => Type::Unknown,
SyntaxShape::String => Type::String,
SyntaxShape::Table => Type::Table,
SyntaxShape::VarWithOptType => Type::Unknown,
SyntaxShape::Variable => Type::Unknown,
}
}
}

View file

@ -0,0 +1,40 @@
use std::fmt::Display;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Type {
Int,
Float,
Bool,
String,
Block,
ColumnPath,
Duration,
FilePath,
Filesize,
List(Box<Type>),
Number,
Nothing,
Table,
Unknown,
}
impl Display for Type {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Type::Block => write!(f, "block"),
Type::Bool => write!(f, "bool"),
Type::ColumnPath => write!(f, "column path"),
Type::Duration => write!(f, "duration"),
Type::FilePath => write!(f, "filepath"),
Type::Filesize => write!(f, "filesize"),
Type::Float => write!(f, "float"),
Type::Int => write!(f, "int"),
Type::List(l) => write!(f, "list<{}>", l),
Type::Nothing => write!(f, "nothing"),
Type::Number => write!(f, "number"),
Type::String => write!(f, "string"),
Type::Table => write!(f, "table"),
Type::Unknown => write!(f, "unknown"),
}
}
}

View file

@ -1,6 +1,6 @@
use std::{cell::RefCell, fmt::Debug, rc::Rc}; use std::{cell::RefCell, fmt::Debug, rc::Rc};
use nu_parser::{BlockId, Span, Type}; use crate::{span, BlockId, Span, Type};
use crate::ShellError; use crate::ShellError;
@ -194,7 +194,7 @@ impl Value {
Value::List { val, .. } => val.into_string(), Value::List { val, .. } => val.into_string(),
Value::Table { headers, val, .. } => val.into_string(headers), Value::Table { headers, val, .. } => val.into_string(headers),
Value::Block { val, .. } => format!("<Block {}>", val), Value::Block { val, .. } => format!("<Block {}>", val),
Value::Nothing { .. } => format!("<Nothing>"), Value::Nothing { .. } => String::new(),
} }
} }
} }
@ -214,7 +214,7 @@ impl PartialEq for Value {
impl Value { impl Value {
pub fn add(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn add(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> {
let span = nu_parser::span(&[self.span(), rhs.span()]); let span = span(&[self.span(), rhs.span()]);
match (self, rhs) { match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Int { (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Int {
@ -248,7 +248,7 @@ impl Value {
} }
} }
pub fn sub(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn sub(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> {
let span = nu_parser::span(&[self.span(), rhs.span()]); let span = span(&[self.span(), rhs.span()]);
match (self, rhs) { match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Int { (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Int {
@ -278,7 +278,7 @@ impl Value {
} }
} }
pub fn mul(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn mul(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> {
let span = nu_parser::span(&[self.span(), rhs.span()]); let span = span(&[self.span(), rhs.span()]);
match (self, rhs) { match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Int { (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Int {
@ -308,7 +308,7 @@ impl Value {
} }
} }
pub fn div(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn div(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> {
let span = nu_parser::span(&[self.span(), rhs.span()]); let span = span(&[self.span(), rhs.span()]);
match (self, rhs) { match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => { (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
@ -362,7 +362,7 @@ impl Value {
} }
} }
pub fn lt(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn lt(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> {
let span = nu_parser::span(&[self.span(), rhs.span()]); let span = span(&[self.span(), rhs.span()]);
match (self, rhs) { match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Bool { (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Bool {
@ -391,7 +391,7 @@ impl Value {
} }
} }
pub fn lte(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn lte(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> {
let span = nu_parser::span(&[self.span(), rhs.span()]); let span = span(&[self.span(), rhs.span()]);
match (self, rhs) { match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Bool { (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Bool {
@ -420,7 +420,7 @@ impl Value {
} }
} }
pub fn gt(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn gt(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> {
let span = nu_parser::span(&[self.span(), rhs.span()]); let span = span(&[self.span(), rhs.span()]);
match (self, rhs) { match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Bool { (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Bool {
@ -449,7 +449,7 @@ impl Value {
} }
} }
pub fn gte(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn gte(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> {
let span = nu_parser::span(&[self.span(), rhs.span()]); let span = span(&[self.span(), rhs.span()]);
match (self, rhs) { match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Bool { (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Bool {
@ -478,7 +478,7 @@ impl Value {
} }
} }
pub fn eq(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn eq(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> {
let span = nu_parser::span(&[self.span(), rhs.span()]); let span = span(&[self.span(), rhs.span()]);
match (self, rhs) { match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Bool { (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Bool {
@ -514,7 +514,7 @@ impl Value {
} }
} }
pub fn ne(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn ne(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> {
let span = nu_parser::span(&[self.span(), rhs.span()]); let span = span(&[self.span(), rhs.span()]);
match (self, rhs) { match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Bool { (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Bool {