diff --git a/Cargo.lock b/Cargo.lock index bbec05e95..2bde0dbf3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -292,14 +292,20 @@ dependencies = [ "nu-ansi-term", "nu-engine", "nu-parser", + "nu-protocol", "reedline", ] +[[package]] +name = "nu-command" +version = "0.1.0" + [[package]] name = "nu-engine" version = "0.1.0" dependencies = [ "nu-parser", + "nu-protocol", ] [[package]] @@ -320,8 +326,13 @@ name = "nu-parser" version = "0.1.0" dependencies = [ "codespan-reporting", + "nu-protocol", ] +[[package]] +name = "nu-protocol" +version = "0.1.0" + [[package]] name = "num-integer" version = "0.1.44" diff --git a/Cargo.toml b/Cargo.toml index 9bf10f63f..73e2375ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [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] reedline = { git = "https://github.com/jntrnr/reedline", branch = "main" } diff --git a/crates/nu-cli/Cargo.toml b/crates/nu-cli/Cargo.toml index 115029612..e5a8ba5e6 100644 --- a/crates/nu-cli/Cargo.toml +++ b/crates/nu-cli/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" [dependencies] nu-engine = { path = "../nu-engine" } nu-parser = { path = "../nu-parser" } +nu-protocol = { path = "../nu-protocol" } codespan-reporting = "0.11.1" nu-ansi-term = "0.32.0" reedline = { git = "https://github.com/jntrnr/reedline", branch = "main" } diff --git a/crates/nu-cli/src/default_context.rs b/crates/nu-cli/src/default_context.rs index 459f04423..d03de7ece 100644 --- a/crates/nu-cli/src/default_context.rs +++ b/crates/nu-cli/src/default_context.rs @@ -1,6 +1,7 @@ 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> { let parser_state = Rc::new(RefCell::new(ParserState::new())); diff --git a/crates/nu-cli/src/errors.rs b/crates/nu-cli/src/errors.rs index e3923042d..b891c22c6 100644 --- a/crates/nu-cli/src/errors.rs +++ b/crates/nu-cli/src/errors.rs @@ -2,8 +2,8 @@ use core::ops::Range; use codespan_reporting::diagnostic::{Diagnostic, Label}; use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; -use nu_engine::ShellError; -use nu_parser::{ParseError, ParserWorkingSet, Span}; +use nu_parser::{ParseError, ParserWorkingSet}; +use nu_protocol::{ShellError, Span}; fn convert_span_to_diag( working_set: &ParserWorkingSet, diff --git a/crates/nu-command/Cargo.toml b/crates/nu-command/Cargo.toml new file mode 100644 index 000000000..eaaba9db1 --- /dev/null +++ b/crates/nu-command/Cargo.toml @@ -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] diff --git a/crates/nu-command/src/length.rs b/crates/nu-command/src/length.rs new file mode 100644 index 000000000..e69de29bb diff --git a/crates/nu-command/src/lib.rs b/crates/nu-command/src/lib.rs new file mode 100644 index 000000000..31e1bb209 --- /dev/null +++ b/crates/nu-command/src/lib.rs @@ -0,0 +1,7 @@ +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} diff --git a/crates/nu-engine/Cargo.toml b/crates/nu-engine/Cargo.toml index 95747a0dc..3fbdb0650 100644 --- a/crates/nu-engine/Cargo.toml +++ b/crates/nu-engine/Cargo.toml @@ -4,4 +4,5 @@ version = "0.1.0" edition = "2018" [dependencies] -nu-parser = { path = "../nu-parser" } \ No newline at end of file +nu-parser = { path = "../nu-parser" } +nu-protocol = { path = "../nu-protocol" } \ No newline at end of file diff --git a/crates/nu-engine/src/eval.rs b/crates/nu-engine/src/eval.rs index dab0bf846..6962e1541 100644 --- a/crates/nu-engine/src/eval.rs +++ b/crates/nu-engine/src/eval.rs @@ -1,26 +1,8 @@ use std::time::Instant; -use crate::{ - state::State, - value::{IntoRowStream, IntoValueStream, 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), -} +use crate::state::State; +use nu_parser::{Block, Call, Expr, Expression, Operator, Statement}; +use nu_protocol::{IntoRowStream, IntoValueStream, ShellError, Span, Value}; pub fn eval_operator(op: &Expression) -> Result { match op { diff --git a/crates/nu-engine/src/lib.rs b/crates/nu-engine/src/lib.rs index 2d0db2a8e..138fe7ba3 100644 --- a/crates/nu-engine/src/lib.rs +++ b/crates/nu-engine/src/lib.rs @@ -1,7 +1,5 @@ mod eval; 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 value::Value; diff --git a/crates/nu-engine/src/state.rs b/crates/nu-engine/src/state.rs index e1a830522..108111aa2 100644 --- a/crates/nu-engine/src/state.rs +++ b/crates/nu-engine/src/state.rs @@ -1,7 +1,7 @@ -use nu_parser::{ParserState, VarId}; +use nu_parser::ParserState; use std::{cell::RefCell, collections::HashMap, rc::Rc}; -use crate::{value::Value, ShellError}; +use nu_protocol::{ShellError, Value, VarId}; pub struct State { pub parser_state: Rc>, diff --git a/crates/nu-parser/Cargo.toml b/crates/nu-parser/Cargo.toml index 13f8ce476..f0ca45a1f 100644 --- a/crates/nu-parser/Cargo.toml +++ b/crates/nu-parser/Cargo.toml @@ -4,4 +4,5 @@ version = "0.1.0" edition = "2018" [dependencies] -codespan-reporting = "0.11.1" \ No newline at end of file +codespan-reporting = "0.11.1" +nu-protocol = { path = "../nu-protocol"} \ No newline at end of file diff --git a/crates/nu-parser/src/errors.rs b/crates/nu-parser/src/errors.rs index 3aee7d07d..a084f9858 100644 --- a/crates/nu-parser/src/errors.rs +++ b/crates/nu-parser/src/errors.rs @@ -1,9 +1,7 @@ -use crate::parser_state::Type; use crate::ParserWorkingSet; +use nu_protocol::{Span, Type}; use std::ops::Range; -pub use crate::Span; - #[derive(Debug)] pub enum ParseError { ExtraTokens(Span), diff --git a/crates/nu-parser/src/flatten.rs b/crates/nu-parser/src/flatten.rs index d62beb0a2..a11887dd4 100644 --- a/crates/nu-parser/src/flatten.rs +++ b/crates/nu-parser/src/flatten.rs @@ -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)] pub enum FlatShape { diff --git a/crates/nu-parser/src/lex.rs b/crates/nu-parser/src/lex.rs index 5a33d87bb..bc2d865b3 100644 --- a/crates/nu-parser/src/lex.rs +++ b/crates/nu-parser/src/lex.rs @@ -1,4 +1,5 @@ -use crate::{ParseError, Span}; +use crate::ParseError; +use nu_protocol::Span; #[derive(Debug, PartialEq, Eq)] pub enum TokenContents { @@ -307,4 +308,4 @@ pub fn lex( } } (output, error) -} \ No newline at end of file +} diff --git a/crates/nu-parser/src/lib.rs b/crates/nu-parser/src/lib.rs index 9c10dd18f..9649078b5 100644 --- a/crates/nu-parser/src/lib.rs +++ b/crates/nu-parser/src/lib.rs @@ -1,23 +1,14 @@ -mod declaration; mod errors; mod flatten; mod lex; mod lite_parse; mod parser; mod parser_state; -mod signature; -mod span; mod type_check; -pub use declaration::Declaration; pub use errors::ParseError; pub use flatten::FlatShape; pub use lex::{lex, Token, TokenContents}; pub use lite_parse::{lite_parse, LiteBlock}; -pub use parser::{ - span, Block, Call, Expr, Expression, Import, Operator, Pipeline, Statement, SyntaxShape, - VarDecl, -}; -pub use parser_state::{BlockId, DeclId, ParserDelta, ParserState, ParserWorkingSet, Type, VarId}; -pub use signature::{Flag, PositionalArg, Signature}; -pub use span::Span; +pub use parser::{Block, Call, Expr, Expression, Import, Operator, Pipeline, Statement, VarDecl}; +pub use parser_state::{ParserDelta, ParserState, ParserWorkingSet}; diff --git a/crates/nu-parser/src/lite_parse.rs b/crates/nu-parser/src/lite_parse.rs index f702701b3..cd5d75931 100644 --- a/crates/nu-parser/src/lite_parse.rs +++ b/crates/nu-parser/src/lite_parse.rs @@ -1,4 +1,5 @@ -use crate::{ParseError, Span, Token, TokenContents}; +use crate::{ParseError, Token, TokenContents}; +use nu_protocol::Span; #[derive(Debug)] pub struct LiteCommand { diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index 4e1a5281a..e3e5c6093 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -3,117 +3,13 @@ use std::{ ops::{Index, IndexMut}, }; -use crate::{ - lex, lite_parse, - parser_state::{Type, VarId}, - signature::{Flag, PositionalArg}, - BlockId, DeclId, Declaration, LiteBlock, ParseError, ParserWorkingSet, Signature, Span, Token, - TokenContents, +use crate::{lex, lite_parse, LiteBlock, ParseError, ParserWorkingSet, Token, TokenContents}; + +use nu_protocol::{ + span, BlockId, DeclId, Declaration, Flag, PositionalArg, Signature, Span, SyntaxShape, Type, + VarId, }; -/// 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, Box), - - /// 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), - - /// 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)] pub enum Operator { Equal, @@ -404,21 +300,6 @@ fn check_call(command: Span, sig: &Signature, call: &Call) -> Option } } -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> { pub fn parse_external_call(&mut self, spans: &[Span]) -> (Expression, Option) { // TODO: add external parsing @@ -725,7 +606,7 @@ impl<'a> ParserWorkingSet<'a> { call.decl_id = decl_id; 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 let mut positional_idx = 0; @@ -738,8 +619,7 @@ impl<'a> ParserWorkingSet<'a> { let arg_span = spans[spans_idx]; // Check if we're on a long flag, if so, parse - let (long_name, arg, err) = - self.parse_long_flag(spans, &mut spans_idx, &decl.signature); + let (long_name, arg, err) = self.parse_long_flag(spans, &mut spans_idx, &signature); if let Some(long_name) = long_name { // We found a long flag, like --bar 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 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 { error = error.or(err); @@ -774,8 +654,9 @@ impl<'a> ParserWorkingSet<'a> { } // 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 + let decl = self.get_decl(decl_id); let end = self.calculate_end_span(&decl, spans, spans_idx, positional_idx); @@ -813,7 +694,7 @@ impl<'a> ParserWorkingSet<'a> { spans_idx += 1; } - let err = check_call(command_span, &decl.signature, &call); + let err = check_call(command_span, &signature, &call); error = error.or(err); // FIXME: type unknown diff --git a/crates/nu-parser/src/parser_state.rs b/crates/nu-parser/src/parser_state.rs index 6dafdb633..b4d1c82d5 100644 --- a/crates/nu-parser/src/parser_state.rs +++ b/crates/nu-parser/src/parser_state.rs @@ -1,8 +1,8 @@ -use crate::{parser::Block, Declaration, Span}; +use crate::parser::Block; 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 { files: Vec<(String, usize, usize)>, file_contents: Vec, @@ -12,49 +12,6 @@ pub struct ParserState { scope: Vec, } -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum Type { - Int, - Float, - Bool, - String, - Block, - ColumnPath, - Duration, - FilePath, - Filesize, - List(Box), - 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)] struct ScopeFrame { vars: HashMap, VarId>, @@ -136,7 +93,7 @@ impl ParserState { pub fn print_decls(&self) { 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> { permanent_state: &'a ParserState, pub delta: ParserDelta, } -#[derive(Debug)] pub struct ParserDelta { files: Vec<(String, usize, usize)>, pub(crate) file_contents: Vec, diff --git a/crates/nu-parser/src/type_check.rs b/crates/nu-parser/src/type_check.rs index 9319e3d5f..65b0697e9 100644 --- a/crates/nu-parser/src/type_check.rs +++ b/crates/nu-parser/src/type_check.rs @@ -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> { pub fn type_compatible(lhs: &Type, rhs: &Type) -> bool { diff --git a/crates/nu-parser/tests/test_lex.rs b/crates/nu-parser/tests/test_lex.rs index 7646db7c8..a93088980 100644 --- a/crates/nu-parser/tests/test_lex.rs +++ b/crates/nu-parser/tests/test_lex.rs @@ -1,4 +1,5 @@ -use nu_parser::{lex, ParseError, Span, Token, TokenContents}; +use nu_parser::{lex, ParseError, Token, TokenContents}; +use nu_protocol::Span; #[test] fn lex_basic() { diff --git a/crates/nu-parser/tests/test_lite_parser.rs b/crates/nu-parser/tests/test_lite_parser.rs index 81c415048..9b739021a 100644 --- a/crates/nu-parser/tests/test_lite_parser.rs +++ b/crates/nu-parser/tests/test_lite_parser.rs @@ -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 { let (output, err) = lex(input, 0, &[], &[]); diff --git a/crates/nu-parser/tests/test_parser.rs b/crates/nu-parser/tests/test_parser.rs index d524d422e..ed38f3ccf 100644 --- a/crates/nu-parser/tests/test_parser.rs +++ b/crates/nu-parser/tests/test_parser.rs @@ -1,5 +1,6 @@ use nu_parser::*; -use nu_parser::{ParseError, ParserState, Signature}; +use nu_parser::{ParseError, ParserState}; +use nu_protocol::{Signature, SyntaxShape}; #[test] pub fn parse_int() { diff --git a/crates/nu-protocol/Cargo.toml b/crates/nu-protocol/Cargo.toml new file mode 100644 index 000000000..c1a398d04 --- /dev/null +++ b/crates/nu-protocol/Cargo.toml @@ -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] diff --git a/crates/nu-protocol/README.md b/crates/nu-protocol/README.md new file mode 100644 index 000000000..9443d74fd --- /dev/null +++ b/crates/nu-protocol/README.md @@ -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. \ No newline at end of file diff --git a/crates/nu-parser/src/declaration.rs b/crates/nu-protocol/src/declaration.rs similarity index 84% rename from crates/nu-parser/src/declaration.rs rename to crates/nu-protocol/src/declaration.rs index 585a1980e..0bb638a33 100644 --- a/crates/nu-parser/src/declaration.rs +++ b/crates/nu-protocol/src/declaration.rs @@ -1,6 +1,5 @@ use crate::{BlockId, Signature}; -#[derive(Clone, Debug)] pub struct Declaration { pub signature: Box, pub body: Option, diff --git a/crates/nu-protocol/src/id.rs b/crates/nu-protocol/src/id.rs new file mode 100644 index 000000000..cf72289f4 --- /dev/null +++ b/crates/nu-protocol/src/id.rs @@ -0,0 +1,3 @@ +pub type VarId = usize; +pub type DeclId = usize; +pub type BlockId = usize; diff --git a/crates/nu-protocol/src/lib.rs b/crates/nu-protocol/src/lib.rs new file mode 100644 index 000000000..919fc2adf --- /dev/null +++ b/crates/nu-protocol/src/lib.rs @@ -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::*; diff --git a/crates/nu-protocol/src/shell_error.rs b/crates/nu-protocol/src/shell_error.rs new file mode 100644 index 000000000..a0786d599 --- /dev/null +++ b/crates/nu-protocol/src/shell_error.rs @@ -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), +} diff --git a/crates/nu-parser/src/signature.rs b/crates/nu-protocol/src/signature.rs similarity index 99% rename from crates/nu-parser/src/signature.rs rename to crates/nu-protocol/src/signature.rs index f2e80d751..f7e4ddea7 100644 --- a/crates/nu-parser/src/signature.rs +++ b/crates/nu-protocol/src/signature.rs @@ -1,4 +1,5 @@ -use crate::{parser::SyntaxShape, Declaration, VarId}; +use crate::VarId; +use crate::{Declaration, SyntaxShape}; #[derive(Debug, Clone)] pub struct Flag { diff --git a/crates/nu-parser/src/span.rs b/crates/nu-protocol/src/span.rs similarity index 60% rename from crates/nu-parser/src/span.rs rename to crates/nu-protocol/src/span.rs index 0777afef6..f1fd06435 100644 --- a/crates/nu-parser/src/span.rs +++ b/crates/nu-protocol/src/span.rs @@ -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, + } + } +} diff --git a/crates/nu-protocol/src/syntax_shape.rs b/crates/nu-protocol/src/syntax_shape.rs new file mode 100644 index 000000000..c62048d17 --- /dev/null +++ b/crates/nu-protocol/src/syntax_shape.rs @@ -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, Box), + + /// 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), + + /// 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, + } + } +} diff --git a/crates/nu-protocol/src/ty.rs b/crates/nu-protocol/src/ty.rs new file mode 100644 index 000000000..80cbc3b5e --- /dev/null +++ b/crates/nu-protocol/src/ty.rs @@ -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), + 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"), + } + } +} diff --git a/crates/nu-engine/src/value.rs b/crates/nu-protocol/src/value.rs similarity index 96% rename from crates/nu-engine/src/value.rs rename to crates/nu-protocol/src/value.rs index 52cf01aaf..bd328eb71 100644 --- a/crates/nu-engine/src/value.rs +++ b/crates/nu-protocol/src/value.rs @@ -1,6 +1,6 @@ use std::{cell::RefCell, fmt::Debug, rc::Rc}; -use nu_parser::{BlockId, Span, Type}; +use crate::{span, BlockId, Span, Type}; use crate::ShellError; @@ -194,7 +194,7 @@ impl Value { Value::List { val, .. } => val.into_string(), Value::Table { headers, val, .. } => val.into_string(headers), Value::Block { val, .. } => format!("", val), - Value::Nothing { .. } => format!(""), + Value::Nothing { .. } => String::new(), } } } @@ -214,7 +214,7 @@ impl PartialEq for Value { impl Value { pub fn add(&self, op: Span, rhs: &Value) -> Result { - let span = nu_parser::span(&[self.span(), rhs.span()]); + let span = span(&[self.span(), rhs.span()]); match (self, rhs) { (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 { - let span = nu_parser::span(&[self.span(), rhs.span()]); + let span = span(&[self.span(), rhs.span()]); match (self, rhs) { (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 { - let span = nu_parser::span(&[self.span(), rhs.span()]); + let span = span(&[self.span(), rhs.span()]); match (self, rhs) { (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 { - let span = nu_parser::span(&[self.span(), rhs.span()]); + let span = span(&[self.span(), rhs.span()]); match (self, rhs) { (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => { @@ -362,7 +362,7 @@ impl Value { } } pub fn lt(&self, op: Span, rhs: &Value) -> Result { - let span = nu_parser::span(&[self.span(), rhs.span()]); + let span = span(&[self.span(), rhs.span()]); match (self, rhs) { (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 { - let span = nu_parser::span(&[self.span(), rhs.span()]); + let span = span(&[self.span(), rhs.span()]); match (self, rhs) { (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 { - let span = nu_parser::span(&[self.span(), rhs.span()]); + let span = span(&[self.span(), rhs.span()]); match (self, rhs) { (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 { - let span = nu_parser::span(&[self.span(), rhs.span()]); + let span = span(&[self.span(), rhs.span()]); match (self, rhs) { (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 { - let span = nu_parser::span(&[self.span(), rhs.span()]); + let span = span(&[self.span(), rhs.span()]); match (self, rhs) { (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 { - let span = nu_parser::span(&[self.span(), rhs.span()]); + let span = span(&[self.span(), rhs.span()]); match (self, rhs) { (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Bool {