mirror of
https://github.com/nushell/nushell
synced 2024-12-28 05:53:09 +00:00
start adding row expr parsing
This commit is contained in:
parent
bf1a23afcf
commit
e540f0ad26
4 changed files with 95 additions and 9 deletions
15
src/main.rs
15
src/main.rs
|
@ -7,6 +7,21 @@ fn main() -> std::io::Result<()> {
|
|||
let sig = Signature::build("foo").named("--jazz", SyntaxShape::Int, "jazz!!", Some('j'));
|
||||
working_set.add_decl((b"foo").to_vec(), sig);
|
||||
|
||||
let sig =
|
||||
Signature::build("where").required("cond", SyntaxShape::RowCondition, "condition");
|
||||
working_set.add_decl((b"where").to_vec(), sig);
|
||||
|
||||
let sig = Signature::build("if")
|
||||
.required("cond", SyntaxShape::RowCondition, "condition")
|
||||
.required("then_block", SyntaxShape::Block, "then block")
|
||||
.required(
|
||||
"else",
|
||||
SyntaxShape::Literal(b"else".to_vec()),
|
||||
"else keyword",
|
||||
)
|
||||
.required("else_block", SyntaxShape::Block, "else block");
|
||||
working_set.add_decl((b"if").to_vec(), sig);
|
||||
|
||||
//let file = std::fs::read(&path)?;
|
||||
//let (output, err) = working_set.parse_file(&path, file);
|
||||
let (output, err) = working_set.parse_source(path.as_bytes());
|
||||
|
|
|
@ -11,39 +11,56 @@ use crate::{
|
|||
pub enum SyntaxShape {
|
||||
/// A specific match to a word or symbol
|
||||
Literal(Vec<u8>),
|
||||
|
||||
/// 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]`
|
||||
Table,
|
||||
|
||||
/// 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 general expression, eg `1 + 2` or `foo --bar`
|
||||
Expression,
|
||||
}
|
||||
|
@ -105,6 +122,7 @@ pub enum Expr {
|
|||
Block(Box<Block>),
|
||||
List(Vec<Expression>),
|
||||
Table(Vec<Expression>, Vec<Vec<Expression>>),
|
||||
Literal(Vec<u8>),
|
||||
String(String), // FIXME: improve this in the future?
|
||||
Garbage,
|
||||
}
|
||||
|
@ -290,6 +308,7 @@ impl ParserWorkingSet {
|
|||
|
||||
if let Some(decl_id) = self.find_decl(name) {
|
||||
let mut call = Call::new();
|
||||
call.decl_id = decl_id;
|
||||
|
||||
let sig = self
|
||||
.get_decl(decl_id)
|
||||
|
@ -402,10 +421,35 @@ impl ParserWorkingSet {
|
|||
}
|
||||
}
|
||||
} else if let Some(positional) = sig.get_positional(positional_idx) {
|
||||
let (arg, err) = self.parse_arg(arg_span, positional.shape);
|
||||
error = error.or(err);
|
||||
match positional.shape {
|
||||
SyntaxShape::RowCondition => {
|
||||
let remainder = sig.num_positionals() - positional_idx;
|
||||
|
||||
call.positional.push(arg);
|
||||
if spans.len() < remainder {
|
||||
error = error.or_else(|| {
|
||||
Some(ParseError::MissingPositional(
|
||||
"required args".into(),
|
||||
arg_span,
|
||||
))
|
||||
});
|
||||
} else {
|
||||
let (arg, err) = self.parse_row_condition(
|
||||
&spans[arg_offset..(spans.len() - remainder + 1)],
|
||||
);
|
||||
error = error.or(err);
|
||||
call.positional.push(arg);
|
||||
|
||||
arg_offset = spans.len() - remainder;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let (arg, err) = self.parse_arg(arg_span, positional.shape);
|
||||
error = error.or(err);
|
||||
|
||||
call.positional.push(arg);
|
||||
}
|
||||
}
|
||||
positional_idx += 1;
|
||||
} else {
|
||||
error = error.or(Some(ParseError::ExtraPositional(arg_span)))
|
||||
}
|
||||
|
@ -584,6 +628,10 @@ impl ParserWorkingSet {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn parse_row_condition(&mut self, spans: &[Span]) -> (Expression, Option<ParseError>) {
|
||||
self.parse_math_expression(spans)
|
||||
}
|
||||
|
||||
pub fn parse_table_expression(&mut self, span: Span) -> (Expression, Option<ParseError>) {
|
||||
let bytes = self.get_span_contents(span);
|
||||
let mut error = None;
|
||||
|
@ -786,7 +834,26 @@ impl ParserWorkingSet {
|
|||
} else {
|
||||
(
|
||||
garbage(span),
|
||||
Some(ParseError::Mismatch("number".into(), span)),
|
||||
Some(ParseError::Mismatch("int".into(), span)),
|
||||
)
|
||||
}
|
||||
}
|
||||
SyntaxShape::Literal(literal) => {
|
||||
if bytes == literal {
|
||||
(
|
||||
Expression {
|
||||
expr: Expr::Literal(literal),
|
||||
span,
|
||||
},
|
||||
None,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
garbage(span),
|
||||
Some(ParseError::Mismatch(
|
||||
format!("keyword '{}'", String::from_utf8_lossy(&literal)),
|
||||
span,
|
||||
)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -815,7 +882,7 @@ impl ParserWorkingSet {
|
|||
}
|
||||
_ => (
|
||||
garbage(span),
|
||||
Some(ParseError::Mismatch("number".into(), span)),
|
||||
Some(ParseError::Mismatch("incomplete parser".into(), span)),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -190,8 +190,8 @@ impl ParserWorkingSet {
|
|||
}
|
||||
|
||||
pub fn find_decl(&self, name: &[u8]) -> Option<DeclId> {
|
||||
for scope in self.scope.iter().rev().enumerate() {
|
||||
if let Some(decl_id) = scope.1.decls.get(name) {
|
||||
for scope in self.scope.iter().rev() {
|
||||
if let Some(decl_id) = scope.decls.get(name) {
|
||||
return Some(*decl_id);
|
||||
}
|
||||
}
|
||||
|
@ -209,8 +209,8 @@ impl ParserWorkingSet {
|
|||
}
|
||||
|
||||
pub fn find_variable(&self, name: &[u8]) -> Option<VarId> {
|
||||
for scope in self.scope.iter().rev().enumerate() {
|
||||
if let Some(var_id) = scope.1.vars.get(name) {
|
||||
for scope in self.scope.iter().rev() {
|
||||
if let Some(var_id) = scope.vars.get(name) {
|
||||
return Some(*var_id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -190,6 +190,10 @@ impl Signature {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn num_positionals(&self) -> usize {
|
||||
self.required_positional.len() + self.optional_positional.len()
|
||||
}
|
||||
|
||||
/// Find the matching long flag
|
||||
pub fn get_long_flag(&self, name: &str) -> Option<Flag> {
|
||||
for flag in &self.named {
|
||||
|
|
Loading…
Reference in a new issue