start adding row expr parsing

This commit is contained in:
JT 2021-07-08 10:55:46 +12:00
parent bf1a23afcf
commit e540f0ad26
4 changed files with 95 additions and 9 deletions

View file

@ -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());

View file

@ -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)),
), ),
} }
} }

View file

@ -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);
} }
} }

View file

@ -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 {