From 3d252a9797d6e4abf7e6537f13cb74b14c5414e5 Mon Sep 17 00:00:00 2001 From: JT Date: Thu, 2 Sep 2021 13:29:43 +1200 Subject: [PATCH] Add nu-protocol --- Cargo.lock | 11 ++ Cargo.toml | 2 +- crates/nu-cli/Cargo.toml | 1 + crates/nu-cli/src/default_context.rs | 3 +- crates/nu-cli/src/errors.rs | 4 +- crates/nu-command/Cargo.toml | 8 + crates/nu-command/src/length.rs | 0 crates/nu-command/src/lib.rs | 7 + crates/nu-engine/Cargo.toml | 3 +- crates/nu-engine/src/eval.rs | 24 +-- crates/nu-engine/src/lib.rs | 4 +- crates/nu-engine/src/state.rs | 4 +- crates/nu-parser/Cargo.toml | 3 +- crates/nu-parser/src/errors.rs | 4 +- crates/nu-parser/src/flatten.rs | 3 +- crates/nu-parser/src/lex.rs | 5 +- crates/nu-parser/src/lib.rs | 13 +- crates/nu-parser/src/lite_parse.rs | 3 +- crates/nu-parser/src/parser.rs | 141 ++---------------- crates/nu-parser/src/parser_state.rs | 53 +------ crates/nu-parser/src/type_check.rs | 3 +- crates/nu-parser/tests/test_lex.rs | 3 +- crates/nu-parser/tests/test_lite_parser.rs | 3 +- crates/nu-parser/tests/test_parser.rs | 3 +- crates/nu-protocol/Cargo.toml | 8 + crates/nu-protocol/README.md | 3 + .../src/declaration.rs | 1 - crates/nu-protocol/src/id.rs | 3 + crates/nu-protocol/src/lib.rs | 17 +++ crates/nu-protocol/src/shell_error.rs | 17 +++ .../src/signature.rs | 3 +- crates/{nu-parser => nu-protocol}/src/span.rs | 15 ++ crates/nu-protocol/src/syntax_shape.rs | 104 +++++++++++++ crates/nu-protocol/src/ty.rs | 40 +++++ .../{nu-engine => nu-protocol}/src/value.rs | 24 +-- 35 files changed, 296 insertions(+), 247 deletions(-) create mode 100644 crates/nu-command/Cargo.toml create mode 100644 crates/nu-command/src/length.rs create mode 100644 crates/nu-command/src/lib.rs create mode 100644 crates/nu-protocol/Cargo.toml create mode 100644 crates/nu-protocol/README.md rename crates/{nu-parser => nu-protocol}/src/declaration.rs (84%) create mode 100644 crates/nu-protocol/src/id.rs create mode 100644 crates/nu-protocol/src/lib.rs create mode 100644 crates/nu-protocol/src/shell_error.rs rename crates/{nu-parser => nu-protocol}/src/signature.rs (99%) rename crates/{nu-parser => nu-protocol}/src/span.rs (60%) create mode 100644 crates/nu-protocol/src/syntax_shape.rs create mode 100644 crates/nu-protocol/src/ty.rs rename crates/{nu-engine => nu-protocol}/src/value.rs (96%) diff --git a/Cargo.lock b/Cargo.lock index bbec05e95a..2bde0dbf30 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 9bf10f63fb..73e2375eed 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 115029612b..e5a8ba5e6f 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 459f04423c..d03de7ece8 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 e3923042df..b891c22c63 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 0000000000..eaaba9db15 --- /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 0000000000..e69de29bb2 diff --git a/crates/nu-command/src/lib.rs b/crates/nu-command/src/lib.rs new file mode 100644 index 0000000000..31e1bb209f --- /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 95747a0dc2..3fbdb06501 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 dab0bf846d..6962e15416 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 2d0db2a8e3..138fe7ba3c 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 e1a8305229..108111aa22 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 13f8ce4764..f0ca45a1fb 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 3aee7d07d3..a084f98587 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 d62beb0a26..a11887dd46 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 5a33d87bb7..bc2d865b31 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 9c10dd18f8..9649078b51 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 f702701b36..cd5d75931b 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 4e1a5281a3..e3e5c60936 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 6dafdb6336..b4d1c82d56 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 9319e3d5f1..65b0697e96 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 7646db7c86..a93088980b 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 81c415048f..9b739021ad 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 d524d422e1..ed38f3ccfd 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 0000000000..c1a398d04e --- /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 0000000000..9443d74fd5 --- /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 585a1980ed..0bb638a33b 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 0000000000..cf72289f43 --- /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 0000000000..919fc2adf0 --- /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 0000000000..a0786d599b --- /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 f2e80d7511..f7e4ddea71 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 0777afef69..f1fd064355 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 0000000000..c62048d17f --- /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 0000000000..80cbc3b5e6 --- /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 52cf01aaf0..bd328eb714 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 {