mirror of
https://github.com/nushell/nushell
synced 2024-12-29 14:33:13 +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'));
|
let sig = Signature::build("foo").named("--jazz", SyntaxShape::Int, "jazz!!", Some('j'));
|
||||||
working_set.add_decl((b"foo").to_vec(), sig);
|
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 file = std::fs::read(&path)?;
|
||||||
//let (output, err) = working_set.parse_file(&path, file);
|
//let (output, err) = working_set.parse_file(&path, file);
|
||||||
let (output, err) = working_set.parse_source(path.as_bytes());
|
let (output, err) = working_set.parse_source(path.as_bytes());
|
||||||
|
|
|
@ -11,39 +11,56 @@ use crate::{
|
||||||
pub enum SyntaxShape {
|
pub enum SyntaxShape {
|
||||||
/// A specific match to a word or symbol
|
/// A specific match to a word or symbol
|
||||||
Literal(Vec<u8>),
|
Literal(Vec<u8>),
|
||||||
|
|
||||||
/// Any syntactic form is allowed
|
/// Any syntactic form is allowed
|
||||||
Any,
|
Any,
|
||||||
|
|
||||||
/// Strings and string-like bare words are allowed
|
/// Strings and string-like bare words are allowed
|
||||||
String,
|
String,
|
||||||
|
|
||||||
/// A dotted path to navigate the table
|
/// A dotted path to navigate the table
|
||||||
ColumnPath,
|
ColumnPath,
|
||||||
|
|
||||||
/// A dotted path to navigate the table (including variable)
|
/// A dotted path to navigate the table (including variable)
|
||||||
FullColumnPath,
|
FullColumnPath,
|
||||||
|
|
||||||
/// Only a numeric (integer or decimal) value is allowed
|
/// Only a numeric (integer or decimal) value is allowed
|
||||||
Number,
|
Number,
|
||||||
|
|
||||||
/// A range is allowed (eg, `1..3`)
|
/// A range is allowed (eg, `1..3`)
|
||||||
Range,
|
Range,
|
||||||
|
|
||||||
/// Only an integer value is allowed
|
/// Only an integer value is allowed
|
||||||
Int,
|
Int,
|
||||||
|
|
||||||
/// A filepath is allowed
|
/// A filepath is allowed
|
||||||
FilePath,
|
FilePath,
|
||||||
|
|
||||||
/// A glob pattern is allowed, eg `foo*`
|
/// A glob pattern is allowed, eg `foo*`
|
||||||
GlobPattern,
|
GlobPattern,
|
||||||
|
|
||||||
/// A block is allowed, eg `{start this thing}`
|
/// A block is allowed, eg `{start this thing}`
|
||||||
Block,
|
Block,
|
||||||
|
|
||||||
/// A table is allowed, eg `[first second]`
|
/// A table is allowed, eg `[first second]`
|
||||||
Table,
|
Table,
|
||||||
|
|
||||||
/// A filesize value is allowed, eg `10kb`
|
/// A filesize value is allowed, eg `10kb`
|
||||||
Filesize,
|
Filesize,
|
||||||
|
|
||||||
/// A duration value is allowed, eg `19day`
|
/// A duration value is allowed, eg `19day`
|
||||||
Duration,
|
Duration,
|
||||||
|
|
||||||
/// An operator
|
/// An operator
|
||||||
Operator,
|
Operator,
|
||||||
|
|
||||||
/// A math expression which expands shorthand forms on the lefthand side, eg `foo > 1`
|
/// 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
|
/// The shorthand allows us to more easily reach columns inside of the row being passed in
|
||||||
RowCondition,
|
RowCondition,
|
||||||
|
|
||||||
/// A general math expression, eg `1 + 2`
|
/// A general math expression, eg `1 + 2`
|
||||||
MathExpression,
|
MathExpression,
|
||||||
|
|
||||||
/// A general expression, eg `1 + 2` or `foo --bar`
|
/// A general expression, eg `1 + 2` or `foo --bar`
|
||||||
Expression,
|
Expression,
|
||||||
}
|
}
|
||||||
|
@ -105,6 +122,7 @@ pub enum Expr {
|
||||||
Block(Box<Block>),
|
Block(Box<Block>),
|
||||||
List(Vec<Expression>),
|
List(Vec<Expression>),
|
||||||
Table(Vec<Expression>, Vec<Vec<Expression>>),
|
Table(Vec<Expression>, Vec<Vec<Expression>>),
|
||||||
|
Literal(Vec<u8>),
|
||||||
String(String), // FIXME: improve this in the future?
|
String(String), // FIXME: improve this in the future?
|
||||||
Garbage,
|
Garbage,
|
||||||
}
|
}
|
||||||
|
@ -290,6 +308,7 @@ impl ParserWorkingSet {
|
||||||
|
|
||||||
if let Some(decl_id) = self.find_decl(name) {
|
if let Some(decl_id) = self.find_decl(name) {
|
||||||
let mut call = Call::new();
|
let mut call = Call::new();
|
||||||
|
call.decl_id = decl_id;
|
||||||
|
|
||||||
let sig = self
|
let sig = self
|
||||||
.get_decl(decl_id)
|
.get_decl(decl_id)
|
||||||
|
@ -402,10 +421,35 @@ impl ParserWorkingSet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if let Some(positional) = sig.get_positional(positional_idx) {
|
} else if let Some(positional) = sig.get_positional(positional_idx) {
|
||||||
|
match positional.shape {
|
||||||
|
SyntaxShape::RowCondition => {
|
||||||
|
let remainder = sig.num_positionals() - positional_idx;
|
||||||
|
|
||||||
|
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);
|
let (arg, err) = self.parse_arg(arg_span, positional.shape);
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
|
|
||||||
call.positional.push(arg);
|
call.positional.push(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
positional_idx += 1;
|
||||||
} else {
|
} else {
|
||||||
error = error.or(Some(ParseError::ExtraPositional(arg_span)))
|
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>) {
|
pub fn parse_table_expression(&mut self, span: Span) -> (Expression, Option<ParseError>) {
|
||||||
let bytes = self.get_span_contents(span);
|
let bytes = self.get_span_contents(span);
|
||||||
let mut error = None;
|
let mut error = None;
|
||||||
|
@ -786,7 +834,26 @@ impl ParserWorkingSet {
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
garbage(span),
|
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),
|
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> {
|
pub fn find_decl(&self, name: &[u8]) -> Option<DeclId> {
|
||||||
for scope in self.scope.iter().rev().enumerate() {
|
for scope in self.scope.iter().rev() {
|
||||||
if let Some(decl_id) = scope.1.decls.get(name) {
|
if let Some(decl_id) = scope.decls.get(name) {
|
||||||
return Some(*decl_id);
|
return Some(*decl_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -209,8 +209,8 @@ impl ParserWorkingSet {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_variable(&self, name: &[u8]) -> Option<VarId> {
|
pub fn find_variable(&self, name: &[u8]) -> Option<VarId> {
|
||||||
for scope in self.scope.iter().rev().enumerate() {
|
for scope in self.scope.iter().rev() {
|
||||||
if let Some(var_id) = scope.1.vars.get(name) {
|
if let Some(var_id) = scope.vars.get(name) {
|
||||||
return Some(*var_id);
|
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
|
/// Find the matching long flag
|
||||||
pub fn get_long_flag(&self, name: &str) -> Option<Flag> {
|
pub fn get_long_flag(&self, name: &str) -> Option<Flag> {
|
||||||
for flag in &self.named {
|
for flag in &self.named {
|
||||||
|
|
Loading…
Reference in a new issue