mirror of
https://github.com/nushell/nushell
synced 2024-11-10 07:04:13 +00:00
Add nu-protocol
This commit is contained in:
parent
c4c4d82bf4
commit
3d252a9797
35 changed files with 296 additions and 247 deletions
11
Cargo.lock
generated
11
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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<RefCell<ParserState>> {
|
||||
let parser_state = Rc::new(RefCell::new(ParserState::new()));
|
||||
|
|
|
@ -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,
|
||||
|
|
8
crates/nu-command/Cargo.toml
Normal file
8
crates/nu-command/Cargo.toml
Normal 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]
|
0
crates/nu-command/src/length.rs
Normal file
0
crates/nu-command/src/length.rs
Normal file
7
crates/nu-command/src/lib.rs
Normal file
7
crates/nu-command/src/lib.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(2 + 2, 4);
|
||||
}
|
||||
}
|
|
@ -4,4 +4,5 @@ version = "0.1.0"
|
|||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
nu-parser = { path = "../nu-parser" }
|
||||
nu-parser = { path = "../nu-parser" }
|
||||
nu-protocol = { path = "../nu-protocol" }
|
|
@ -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<Operator, ShellError> {
|
||||
match op {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<RefCell<ParserState>>,
|
||||
|
|
|
@ -4,4 +4,5 @@ version = "0.1.0"
|
|||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
codespan-reporting = "0.11.1"
|
||||
codespan-reporting = "0.11.1"
|
||||
nu-protocol = { path = "../nu-protocol"}
|
|
@ -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),
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::{ParseError, Span, Token, TokenContents};
|
||||
use crate::{ParseError, Token, TokenContents};
|
||||
use nu_protocol::Span;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LiteCommand {
|
||||
|
|
|
@ -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<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)]
|
||||
pub enum Operator {
|
||||
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> {
|
||||
pub fn parse_external_call(&mut self, spans: &[Span]) -> (Expression, Option<ParseError>) {
|
||||
// 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
|
||||
|
|
|
@ -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<u8>,
|
||||
|
@ -12,49 +12,6 @@ pub struct ParserState {
|
|||
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)]
|
||||
struct ScopeFrame {
|
||||
vars: HashMap<Vec<u8>, 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<u8>,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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> {
|
||||
let (output, err) = lex(input, 0, &[], &[]);
|
||||
|
|
|
@ -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() {
|
||||
|
|
8
crates/nu-protocol/Cargo.toml
Normal file
8
crates/nu-protocol/Cargo.toml
Normal 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]
|
3
crates/nu-protocol/README.md
Normal file
3
crates/nu-protocol/README.md
Normal 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.
|
|
@ -1,6 +1,5 @@
|
|||
use crate::{BlockId, Signature};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Declaration {
|
||||
pub signature: Box<Signature>,
|
||||
pub body: Option<BlockId>,
|
3
crates/nu-protocol/src/id.rs
Normal file
3
crates/nu-protocol/src/id.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
pub type VarId = usize;
|
||||
pub type DeclId = usize;
|
||||
pub type BlockId = usize;
|
17
crates/nu-protocol/src/lib.rs
Normal file
17
crates/nu-protocol/src/lib.rs
Normal 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::*;
|
17
crates/nu-protocol/src/shell_error.rs
Normal file
17
crates/nu-protocol/src/shell_error.rs
Normal 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),
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
use crate::{parser::SyntaxShape, Declaration, VarId};
|
||||
use crate::VarId;
|
||||
use crate::{Declaration, SyntaxShape};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Flag {
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
104
crates/nu-protocol/src/syntax_shape.rs
Normal file
104
crates/nu-protocol/src/syntax_shape.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
40
crates/nu-protocol/src/ty.rs
Normal file
40
crates/nu-protocol/src/ty.rs
Normal 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"),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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!("<Block {}>", val),
|
||||
Value::Nothing { .. } => format!("<Nothing>"),
|
||||
Value::Nothing { .. } => String::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -214,7 +214,7 @@ impl PartialEq for Value {
|
|||
|
||||
impl Value {
|
||||
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) {
|
||||
(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> {
|
||||
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<Value, ShellError> {
|
||||
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<Value, ShellError> {
|
||||
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<Value, ShellError> {
|
||||
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<Value, ShellError> {
|
||||
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<Value, ShellError> {
|
||||
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<Value, ShellError> {
|
||||
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<Value, ShellError> {
|
||||
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<Value, ShellError> {
|
||||
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 {
|
Loading…
Reference in a new issue