mirror of
https://github.com/nushell/nushell.git
synced 2025-01-03 13:00:08 +01:00
fix clippy, add strings and concat
This commit is contained in:
parent
a8366ebf15
commit
2eeceae613
@ -6,5 +6,5 @@ edition = "2018"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
reedline = {path = "../reedline"}
|
reedline = {git = "https://github.com/jntrnr/reedline"}
|
||||||
nu-ansi-term = "0.32.0"
|
nu-ansi-term = "0.32.0"
|
@ -2,6 +2,6 @@ use crate::{BlockId, Signature};
|
|||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Declaration {
|
pub struct Declaration {
|
||||||
pub signature: Signature,
|
pub signature: Box<Signature>,
|
||||||
pub body: Option<BlockId>,
|
pub body: Option<BlockId>,
|
||||||
}
|
}
|
||||||
|
92
src/eval.rs
92
src/eval.rs
@ -27,6 +27,11 @@ impl Value {
|
|||||||
val: lhs + rhs,
|
val: lhs + rhs,
|
||||||
span: Span::unknown(),
|
span: Span::unknown(),
|
||||||
}),
|
}),
|
||||||
|
(Value::String { val: lhs, .. }, Value::String { val: rhs, .. }) => Ok(Value::String {
|
||||||
|
val: lhs.to_string() + rhs,
|
||||||
|
span: Span::unknown(),
|
||||||
|
}),
|
||||||
|
|
||||||
_ => Ok(Value::Unknown),
|
_ => Ok(Value::Unknown),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,56 +92,54 @@ fn eval_call(state: &State, stack: &mut Stack, call: &Call) -> Result<Value, She
|
|||||||
}
|
}
|
||||||
let block = state.parser_state.get_block(block_id);
|
let block = state.parser_state.get_block(block_id);
|
||||||
eval_block(state, stack, block)
|
eval_block(state, stack, block)
|
||||||
} else {
|
} else if decl.signature.name == "let" {
|
||||||
if decl.signature.name == "let" {
|
let var_id = call.positional[0]
|
||||||
let var_id = call.positional[0]
|
.as_var()
|
||||||
.as_var()
|
.expect("internal error: missing variable");
|
||||||
.expect("internal error: missing variable");
|
|
||||||
|
|
||||||
let keyword_expr = call.positional[1]
|
let keyword_expr = call.positional[1]
|
||||||
.as_keyword()
|
.as_keyword()
|
||||||
.expect("internal error: missing keyword");
|
.expect("internal error: missing keyword");
|
||||||
|
|
||||||
let rhs = eval_expression(state, stack, keyword_expr)?;
|
let rhs = eval_expression(state, stack, keyword_expr)?;
|
||||||
|
|
||||||
println!("Adding: {:?} to {}", rhs, var_id);
|
println!("Adding: {:?} to {}", rhs, var_id);
|
||||||
|
|
||||||
stack.add_var(var_id, rhs);
|
stack.add_var(var_id, rhs);
|
||||||
Ok(Value::Unknown)
|
Ok(Value::Unknown)
|
||||||
} else if decl.signature.name == "if" {
|
} else if decl.signature.name == "if" {
|
||||||
let cond = &call.positional[0];
|
let cond = &call.positional[0];
|
||||||
let then_block = call.positional[1]
|
let then_block = call.positional[1]
|
||||||
.as_block()
|
.as_block()
|
||||||
.expect("internal error: expected block");
|
.expect("internal error: expected block");
|
||||||
let else_case = call.positional.get(2);
|
let else_case = call.positional.get(2);
|
||||||
|
|
||||||
let result = eval_expression(state, stack, cond)?;
|
let result = eval_expression(state, stack, cond)?;
|
||||||
match result {
|
match result {
|
||||||
Value::Bool { val, .. } => {
|
Value::Bool { val, .. } => {
|
||||||
if val {
|
if val {
|
||||||
let block = state.parser_state.get_block(then_block);
|
let block = state.parser_state.get_block(then_block);
|
||||||
eval_block(state, stack, block)
|
eval_block(state, stack, block)
|
||||||
} else if let Some(else_case) = else_case {
|
} else if let Some(else_case) = else_case {
|
||||||
println!("{:?}", else_case);
|
println!("{:?}", else_case);
|
||||||
if let Some(else_expr) = else_case.as_keyword() {
|
if let Some(else_expr) = else_case.as_keyword() {
|
||||||
if let Some(block_id) = else_expr.as_block() {
|
if let Some(block_id) = else_expr.as_block() {
|
||||||
let block = state.parser_state.get_block(block_id);
|
let block = state.parser_state.get_block(block_id);
|
||||||
eval_block(state, stack, block)
|
eval_block(state, stack, block)
|
||||||
} else {
|
|
||||||
eval_expression(state, stack, else_expr)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
eval_expression(state, stack, else_case)
|
eval_expression(state, stack, else_expr)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(Value::Unknown)
|
eval_expression(state, stack, else_case)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Ok(Value::Unknown)
|
||||||
}
|
}
|
||||||
_ => Err(ShellError::Mismatch("bool".into(), Span::unknown())),
|
|
||||||
}
|
}
|
||||||
} else {
|
_ => Err(ShellError::Mismatch("bool".into(), Span::unknown())),
|
||||||
Ok(Value::Unknown)
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Ok(Value::Unknown)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,9 +162,9 @@ pub fn eval_expression(
|
|||||||
Expr::ExternalCall(_, _) => Err(ShellError::Unsupported(expr.span)),
|
Expr::ExternalCall(_, _) => Err(ShellError::Unsupported(expr.span)),
|
||||||
Expr::Operator(_) => Ok(Value::Unknown),
|
Expr::Operator(_) => Ok(Value::Unknown),
|
||||||
Expr::BinaryOp(lhs, op, rhs) => {
|
Expr::BinaryOp(lhs, op, rhs) => {
|
||||||
let lhs = eval_expression(state, stack, &lhs)?;
|
let lhs = eval_expression(state, stack, lhs)?;
|
||||||
let op = eval_operator(state, stack, &op)?;
|
let op = eval_operator(state, stack, op)?;
|
||||||
let rhs = eval_expression(state, stack, &rhs)?;
|
let rhs = eval_expression(state, stack, rhs)?;
|
||||||
|
|
||||||
match op {
|
match op {
|
||||||
Operator::Plus => lhs.add(&rhs),
|
Operator::Plus => lhs.add(&rhs),
|
||||||
@ -197,11 +200,8 @@ pub fn eval_block(state: &State, stack: &mut Stack, block: &Block) -> Result<Val
|
|||||||
let mut last = Ok(Value::Unknown);
|
let mut last = Ok(Value::Unknown);
|
||||||
|
|
||||||
for stmt in &block.stmts {
|
for stmt in &block.stmts {
|
||||||
match stmt {
|
if let Statement::Expression(expression) = stmt {
|
||||||
Statement::Expression(expression) => {
|
last = Ok(eval_expression(state, stack, expression)?);
|
||||||
last = Ok(eval_expression(state, stack, expression)?);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,15 +35,14 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
match &expr.expr {
|
match &expr.expr {
|
||||||
Expr::BinaryOp(lhs, op, rhs) => {
|
Expr::BinaryOp(lhs, op, rhs) => {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
output.extend(self.flatten_expression(&lhs));
|
output.extend(self.flatten_expression(lhs));
|
||||||
output.extend(self.flatten_expression(&op));
|
output.extend(self.flatten_expression(op));
|
||||||
output.extend(self.flatten_expression(&rhs));
|
output.extend(self.flatten_expression(rhs));
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
Expr::Block(block_id) => self.flatten_block(self.get_block(*block_id)),
|
Expr::Block(block_id) => self.flatten_block(self.get_block(*block_id)),
|
||||||
Expr::Call(call) => {
|
Expr::Call(call) => {
|
||||||
let mut output = vec![];
|
let mut output = vec![(call.head, FlatShape::InternalCall)];
|
||||||
output.push((call.head, FlatShape::InternalCall));
|
|
||||||
for positional in &call.positional {
|
for positional in &call.positional {
|
||||||
output.extend(self.flatten_expression(positional));
|
output.extend(self.flatten_expression(positional));
|
||||||
}
|
}
|
||||||
|
@ -163,7 +163,13 @@ pub fn lex_item(
|
|||||||
// synthetic closing characters to the accumulated token.
|
// synthetic closing characters to the accumulated token.
|
||||||
if let Some(block) = block_level.last() {
|
if let Some(block) = block_level.last() {
|
||||||
let delim = block.closing();
|
let delim = block.closing();
|
||||||
let cause = ParseError::UnexpectedEof((delim as char).to_string(), span);
|
let cause = ParseError::UnexpectedEof(
|
||||||
|
(delim as char).to_string(),
|
||||||
|
Span {
|
||||||
|
start: span.end - 1,
|
||||||
|
end: span.end,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
return (span, Some(cause));
|
return (span, Some(cause));
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ mod span;
|
|||||||
mod syntax_highlight;
|
mod syntax_highlight;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
mod type_check;
|
||||||
|
|
||||||
pub use declaration::Declaration;
|
pub use declaration::Declaration;
|
||||||
pub use eval::{eval_block, eval_expression, Stack, State};
|
pub use eval::{eval_block, eval_expression, Stack, State};
|
||||||
|
@ -163,7 +163,7 @@ fn main() -> std::io::Result<()> {
|
|||||||
println!("Error: {:?}", err);
|
println!("Error: {:?}", err);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// println!("Error: {:?}", err);
|
println!("Error: {:?}", err);
|
||||||
(output, working_set.render())
|
(output, working_set.render())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
279
src/parser.rs
279
src/parser.rs
@ -173,7 +173,7 @@ pub enum Expr {
|
|||||||
Table(Vec<Expression>, Vec<Vec<Expression>>),
|
Table(Vec<Expression>, Vec<Vec<Expression>>),
|
||||||
Keyword(Vec<u8>, Box<Expression>),
|
Keyword(Vec<u8>, Box<Expression>),
|
||||||
String(String), // FIXME: improve this in the future?
|
String(String), // FIXME: improve this in the future?
|
||||||
Signature(Signature),
|
Signature(Box<Signature>),
|
||||||
Garbage,
|
Garbage,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,7 +225,7 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_signature(&self) -> Option<Signature> {
|
pub fn as_signature(&self) -> Option<Box<Signature>> {
|
||||||
match &self.expr {
|
match &self.expr {
|
||||||
Expr::Signature(sig) => Some(sig.clone()),
|
Expr::Signature(sig) => Some(sig.clone()),
|
||||||
_ => None,
|
_ => None,
|
||||||
@ -502,10 +502,7 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
if positional.shape == SyntaxShape::Int
|
if positional.shape == SyntaxShape::Int
|
||||||
|| positional.shape == SyntaxShape::Number
|
|| positional.shape == SyntaxShape::Number
|
||||||
{
|
{
|
||||||
if String::from_utf8_lossy(&arg_contents)
|
if String::from_utf8_lossy(arg_contents).parse::<f64>().is_ok() {
|
||||||
.parse::<f64>()
|
|
||||||
.is_ok()
|
|
||||||
{
|
|
||||||
return (None, None);
|
return (None, None);
|
||||||
} else if let Some(first) = unmatched_short_flags.first() {
|
} else if let Some(first) = unmatched_short_flags.first() {
|
||||||
error = error.or(Some(ParseError::UnknownFlag(*first)));
|
error = error.or(Some(ParseError::UnknownFlag(*first)));
|
||||||
@ -547,21 +544,20 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
|
|
||||||
let mut next_keyword_idx = spans.len();
|
let mut next_keyword_idx = spans.len();
|
||||||
for idx in (positional_idx + 1)..decl.signature.num_positionals() {
|
for idx in (positional_idx + 1)..decl.signature.num_positionals() {
|
||||||
match decl.signature.get_positional(idx) {
|
if let Some(PositionalArg {
|
||||||
Some(PositionalArg {
|
shape: SyntaxShape::Keyword(kw, ..),
|
||||||
shape: SyntaxShape::Keyword(kw, ..),
|
..
|
||||||
..
|
}) = decl.signature.get_positional(idx)
|
||||||
}) => {
|
{
|
||||||
for span_idx in spans_idx..spans.len() {
|
#[allow(clippy::needless_range_loop)]
|
||||||
let contents = self.get_span_contents(spans[span_idx]);
|
for span_idx in spans_idx..spans.len() {
|
||||||
|
let contents = self.get_span_contents(spans[span_idx]);
|
||||||
|
|
||||||
if contents == kw {
|
if contents == kw {
|
||||||
next_keyword_idx = span_idx - (idx - (positional_idx + 1));
|
next_keyword_idx = span_idx - (idx - (positional_idx + 1));
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -575,8 +571,8 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
let end = [next_keyword_idx, remainder_idx, spans.len()]
|
let end = [next_keyword_idx, remainder_idx, spans.len()]
|
||||||
.iter()
|
.iter()
|
||||||
.min()
|
.min()
|
||||||
.expect("internal error: can't find min")
|
.copied()
|
||||||
.clone();
|
.expect("internal error: can't find min");
|
||||||
|
|
||||||
// println!(
|
// println!(
|
||||||
// "{:?}",
|
// "{:?}",
|
||||||
@ -633,17 +629,19 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
// go ahead and override the current error and tell the user about the missing
|
// go ahead and override the current error and tell the user about the missing
|
||||||
// keyword/literal.
|
// keyword/literal.
|
||||||
error = Some(ParseError::Mismatch(
|
error = Some(ParseError::Mismatch(
|
||||||
String::from_utf8_lossy(&keyword).into(),
|
String::from_utf8_lossy(keyword).into(),
|
||||||
arg_span,
|
arg_span,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
*spans_idx += 1;
|
*spans_idx += 1;
|
||||||
if *spans_idx >= spans.len() {
|
if *spans_idx >= spans.len() {
|
||||||
error = error.or(Some(ParseError::MissingPositional(
|
error = error.or_else(|| {
|
||||||
String::from_utf8_lossy(&keyword).into(),
|
Some(ParseError::MissingPositional(
|
||||||
spans[*spans_idx - 1],
|
String::from_utf8_lossy(keyword).into(),
|
||||||
)));
|
spans[*spans_idx - 1],
|
||||||
|
))
|
||||||
|
});
|
||||||
return (
|
return (
|
||||||
Expression {
|
Expression {
|
||||||
expr: Expr::Keyword(
|
expr: Expr::Keyword(
|
||||||
@ -656,7 +654,7 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
error,
|
error,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let (expr, err) = self.parse_multispan_value(&spans, spans_idx, arg);
|
let (expr, err) = self.parse_multispan_value(spans, spans_idx, arg);
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
let ty = expr.ty.clone();
|
let ty = expr.ty.clone();
|
||||||
|
|
||||||
@ -669,11 +667,11 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
error,
|
error,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
x => {
|
_ => {
|
||||||
// All other cases are single-span values
|
// All other cases are single-span values
|
||||||
let arg_span = spans[*spans_idx];
|
let arg_span = spans[*spans_idx];
|
||||||
|
|
||||||
let (arg, err) = self.parse_value(arg_span, &shape);
|
let (arg, err) = self.parse_value(arg_span, shape);
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
|
|
||||||
(arg, error)
|
(arg, error)
|
||||||
@ -756,10 +754,9 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
&& arg.ty != positional.shape.to_type()
|
&& arg.ty != positional.shape.to_type()
|
||||||
{
|
{
|
||||||
let span = span(&spans[orig_idx..spans_idx]);
|
let span = span(&spans[orig_idx..spans_idx]);
|
||||||
error = error.or(Some(ParseError::TypeMismatch(
|
error = error.or_else(|| {
|
||||||
positional.shape.to_type(),
|
Some(ParseError::TypeMismatch(positional.shape.to_type(), span))
|
||||||
span,
|
});
|
||||||
)));
|
|
||||||
Expression::garbage(span)
|
Expression::garbage(span)
|
||||||
} else {
|
} else {
|
||||||
arg
|
arg
|
||||||
@ -940,8 +937,12 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
// this seems okay to set it to unknown here, but we should double-check
|
// this seems okay to set it to unknown here, but we should double-check
|
||||||
let id = self.add_variable(name, Type::Unknown);
|
let id = self.add_variable(name, Type::Unknown);
|
||||||
(
|
(
|
||||||
Expression::garbage(span),
|
Expression {
|
||||||
Some(ParseError::VariableNotFound(span)),
|
expr: Expr::Var(id),
|
||||||
|
span,
|
||||||
|
ty: Type::Unknown,
|
||||||
|
},
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -978,7 +979,7 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
|
|
||||||
let source = self.get_span_contents(span);
|
let source = self.get_span_contents(span);
|
||||||
|
|
||||||
let (output, err) = lex(&source, start, &[], &[]);
|
let (output, err) = lex(source, start, &[], &[]);
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
|
|
||||||
let (output, err) = lite_parse(&output);
|
let (output, err) = lite_parse(&output);
|
||||||
@ -1001,6 +1002,13 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
|
|
||||||
pub fn parse_string(&mut self, span: Span) -> (Expression, Option<ParseError>) {
|
pub fn parse_string(&mut self, span: Span) -> (Expression, Option<ParseError>) {
|
||||||
let bytes = self.get_span_contents(span);
|
let bytes = self.get_span_contents(span);
|
||||||
|
let bytes = if (bytes.starts_with(b"\"") && bytes.ends_with(b"\"") && bytes.len() > 1)
|
||||||
|
|| (bytes.starts_with(b"\'") && bytes.ends_with(b"\'") && bytes.len() > 1)
|
||||||
|
{
|
||||||
|
&bytes[1..(bytes.len() - 1)]
|
||||||
|
} else {
|
||||||
|
bytes
|
||||||
|
};
|
||||||
|
|
||||||
if let Ok(token) = String::from_utf8(bytes.into()) {
|
if let Ok(token) = String::from_utf8(bytes.into()) {
|
||||||
(
|
(
|
||||||
@ -1144,7 +1152,7 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
let span = Span { start, end };
|
let span = Span { start, end };
|
||||||
let source = self.get_span_contents(span);
|
let source = self.get_span_contents(span);
|
||||||
|
|
||||||
let (output, err) = lex(&source, span.start, &[b'\n', b','], &[b':']);
|
let (output, err) = lex(source, span.start, &[b'\n', b','], &[b':']);
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
|
|
||||||
let mut args: Vec<Arg> = vec![];
|
let mut args: Vec<Arg> = vec![];
|
||||||
@ -1166,7 +1174,8 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
}
|
}
|
||||||
ParseMode::TypeMode => {
|
ParseMode::TypeMode => {
|
||||||
// We're seeing two types for the same thing for some reason, error
|
// We're seeing two types for the same thing for some reason, error
|
||||||
error = error.or(Some(ParseError::Mismatch("type".into(), span)));
|
error = error
|
||||||
|
.or_else(|| Some(ParseError::Mismatch("type".into(), span)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1197,17 +1206,19 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
let short_flag = if !short_flag.starts_with(b"-")
|
let short_flag = if !short_flag.starts_with(b"-")
|
||||||
|| !short_flag.ends_with(b")")
|
|| !short_flag.ends_with(b")")
|
||||||
{
|
{
|
||||||
error = error.or(Some(ParseError::Mismatch(
|
error = error.or_else(|| {
|
||||||
"short flag".into(),
|
Some(ParseError::Mismatch(
|
||||||
span,
|
"short flag".into(),
|
||||||
)));
|
span,
|
||||||
|
))
|
||||||
|
});
|
||||||
short_flag
|
short_flag
|
||||||
} else {
|
} else {
|
||||||
&short_flag[1..(short_flag.len() - 1)]
|
&short_flag[1..(short_flag.len() - 1)]
|
||||||
};
|
};
|
||||||
|
|
||||||
let short_flag =
|
let short_flag =
|
||||||
String::from_utf8_lossy(&short_flag).to_string();
|
String::from_utf8_lossy(short_flag).to_string();
|
||||||
let chars: Vec<char> = short_flag.chars().collect();
|
let chars: Vec<char> = short_flag.chars().collect();
|
||||||
let long = String::from_utf8_lossy(&flags[0]).to_string();
|
let long = String::from_utf8_lossy(&flags[0]).to_string();
|
||||||
let variable_name = flags[0][2..].to_vec();
|
let variable_name = flags[0][2..].to_vec();
|
||||||
@ -1224,10 +1235,12 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
var_id: Some(var_id),
|
var_id: Some(var_id),
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
error = error.or(Some(ParseError::Mismatch(
|
error = error.or_else(|| {
|
||||||
"short flag".into(),
|
Some(ParseError::Mismatch(
|
||||||
span,
|
"short flag".into(),
|
||||||
)));
|
span,
|
||||||
|
))
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if contents.starts_with(b"-") && contents.len() > 1 {
|
} else if contents.starts_with(b"-") && contents.len() > 1 {
|
||||||
@ -1239,10 +1252,9 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
let chars: Vec<char> = short_flag.chars().collect();
|
let chars: Vec<char> = short_flag.chars().collect();
|
||||||
|
|
||||||
if chars.len() > 1 {
|
if chars.len() > 1 {
|
||||||
error = error.or(Some(ParseError::Mismatch(
|
error = error.or_else(|| {
|
||||||
"short flag".into(),
|
Some(ParseError::Mismatch("short flag".into(), span))
|
||||||
span,
|
});
|
||||||
)));
|
|
||||||
|
|
||||||
args.push(Arg::Flag(Flag {
|
args.push(Arg::Flag(Flag {
|
||||||
arg: None,
|
arg: None,
|
||||||
@ -1272,10 +1284,9 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
let short_flag = &contents[2..];
|
let short_flag = &contents[2..];
|
||||||
|
|
||||||
let short_flag = if !short_flag.ends_with(b")") {
|
let short_flag = if !short_flag.ends_with(b")") {
|
||||||
error = error.or(Some(ParseError::Mismatch(
|
error = error.or_else(|| {
|
||||||
"short flag".into(),
|
Some(ParseError::Mismatch("short flag".into(), span))
|
||||||
span,
|
});
|
||||||
)));
|
|
||||||
short_flag
|
short_flag
|
||||||
} else {
|
} else {
|
||||||
&short_flag[..(short_flag.len() - 1)]
|
&short_flag[..(short_flag.len() - 1)]
|
||||||
@ -1289,62 +1300,62 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
match args.last_mut() {
|
match args.last_mut() {
|
||||||
Some(Arg::Flag(flag)) => {
|
Some(Arg::Flag(flag)) => {
|
||||||
if flag.short.is_some() {
|
if flag.short.is_some() {
|
||||||
error = error.or(Some(ParseError::Mismatch(
|
error = error.or_else(|| {
|
||||||
"one short flag".into(),
|
Some(ParseError::Mismatch(
|
||||||
span,
|
"one short flag".into(),
|
||||||
)));
|
span,
|
||||||
|
))
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
flag.short = Some(chars[0]);
|
flag.short = Some(chars[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
error = error.or(Some(ParseError::Mismatch(
|
error = error.or_else(|| {
|
||||||
"unknown flag".into(),
|
Some(ParseError::Mismatch(
|
||||||
span,
|
"unknown flag".into(),
|
||||||
)));
|
span,
|
||||||
|
))
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error = error.or(Some(ParseError::Mismatch(
|
error = error.or_else(|| {
|
||||||
"short flag".into(),
|
Some(ParseError::Mismatch("short flag".into(), span))
|
||||||
span,
|
});
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
|
} else if contents.ends_with(b"?") {
|
||||||
|
let contents: Vec<_> = contents[..(contents.len() - 1)].into();
|
||||||
|
let name = String::from_utf8_lossy(&contents).to_string();
|
||||||
|
|
||||||
|
let var_id = self.add_variable(contents, Type::Unknown);
|
||||||
|
|
||||||
|
// Positional arg, optional
|
||||||
|
args.push(Arg::Positional(
|
||||||
|
PositionalArg {
|
||||||
|
desc: String::new(),
|
||||||
|
name,
|
||||||
|
shape: SyntaxShape::Any,
|
||||||
|
var_id: Some(var_id),
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
if contents.ends_with(b"?") {
|
let name = String::from_utf8_lossy(contents).to_string();
|
||||||
let contents: Vec<_> =
|
let contents_vec = contents.to_vec();
|
||||||
contents[..(contents.len() - 1)].into();
|
|
||||||
let name = String::from_utf8_lossy(&contents).to_string();
|
|
||||||
|
|
||||||
let var_id =
|
let var_id = self.add_variable(contents_vec, Type::Unknown);
|
||||||
self.add_variable(contents.into(), Type::Unknown);
|
|
||||||
|
|
||||||
// Positional arg, optional
|
// Positional arg, required
|
||||||
args.push(Arg::Positional(
|
args.push(Arg::Positional(
|
||||||
PositionalArg {
|
PositionalArg {
|
||||||
desc: String::new(),
|
desc: String::new(),
|
||||||
name,
|
name,
|
||||||
shape: SyntaxShape::Any,
|
shape: SyntaxShape::Any,
|
||||||
var_id: Some(var_id),
|
var_id: Some(var_id),
|
||||||
},
|
},
|
||||||
false,
|
true,
|
||||||
))
|
))
|
||||||
} else {
|
|
||||||
let name = String::from_utf8_lossy(contents).to_string();
|
|
||||||
let contents_vec = contents.to_vec();
|
|
||||||
let var_id = self.add_variable(contents_vec, Type::Unknown);
|
|
||||||
|
|
||||||
// Positional arg, required
|
|
||||||
args.push(Arg::Positional(
|
|
||||||
PositionalArg {
|
|
||||||
desc: String::new(),
|
|
||||||
name,
|
|
||||||
shape: SyntaxShape::Any,
|
|
||||||
var_id: Some(var_id),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ParseMode::TypeMode => {
|
ParseMode::TypeMode => {
|
||||||
@ -1387,13 +1398,13 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
match last {
|
match last {
|
||||||
Arg::Flag(flag) => {
|
Arg::Flag(flag) => {
|
||||||
if !flag.desc.is_empty() {
|
if !flag.desc.is_empty() {
|
||||||
flag.desc.push_str("\n");
|
flag.desc.push('\n');
|
||||||
}
|
}
|
||||||
flag.desc.push_str(&contents);
|
flag.desc.push_str(&contents);
|
||||||
}
|
}
|
||||||
Arg::Positional(positional, ..) => {
|
Arg::Positional(positional, ..) => {
|
||||||
if !positional.desc.is_empty() {
|
if !positional.desc.is_empty() {
|
||||||
positional.desc.push_str("\n");
|
positional.desc.push('\n');
|
||||||
}
|
}
|
||||||
positional.desc.push_str(&contents);
|
positional.desc.push_str(&contents);
|
||||||
}
|
}
|
||||||
@ -1431,7 +1442,7 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
|
|
||||||
(
|
(
|
||||||
Expression {
|
Expression {
|
||||||
expr: Expr::Signature(sig),
|
expr: Expr::Signature(Box::new(sig)),
|
||||||
span,
|
span,
|
||||||
ty: Type::Unknown,
|
ty: Type::Unknown,
|
||||||
},
|
},
|
||||||
@ -1471,7 +1482,7 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
let span = Span { start, end };
|
let span = Span { start, end };
|
||||||
let source = self.get_span_contents(span);
|
let source = self.get_span_contents(span);
|
||||||
|
|
||||||
let (output, err) = lex(&source, span.start, &[b'\n', b','], &[]);
|
let (output, err) = lex(source, span.start, &[b'\n', b','], &[]);
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
|
|
||||||
let (output, err) = lite_parse(&output);
|
let (output, err) = lite_parse(&output);
|
||||||
@ -1533,7 +1544,7 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
|
|
||||||
let source = self.get_span_contents(span);
|
let source = self.get_span_contents(span);
|
||||||
|
|
||||||
let (output, err) = lex(&source, start, &[b'\n', b','], &[]);
|
let (output, err) = lex(source, start, &[b'\n', b','], &[]);
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
|
|
||||||
let (output, err) = lite_parse(&output);
|
let (output, err) = lite_parse(&output);
|
||||||
@ -1625,7 +1636,7 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
|
|
||||||
let source = self.get_span_contents(span);
|
let source = self.get_span_contents(span);
|
||||||
|
|
||||||
let (output, err) = lex(&source, start, &[], &[]);
|
let (output, err) = lex(source, start, &[], &[]);
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
|
|
||||||
let (output, err) = lite_parse(&output);
|
let (output, err) = lite_parse(&output);
|
||||||
@ -1726,7 +1737,7 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
}
|
}
|
||||||
SyntaxShape::List(elem) => {
|
SyntaxShape::List(elem) => {
|
||||||
if bytes.starts_with(b"[") {
|
if bytes.starts_with(b"[") {
|
||||||
self.parse_list_expression(span, &elem)
|
self.parse_list_expression(span, elem)
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
Expression::garbage(span),
|
Expression::garbage(span),
|
||||||
@ -1919,64 +1930,12 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
(output, error)
|
(output, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn math_result_type(
|
|
||||||
&self,
|
|
||||||
lhs: &mut Expression,
|
|
||||||
op: &mut Expression,
|
|
||||||
rhs: &mut Expression,
|
|
||||||
) -> (Type, Option<ParseError>) {
|
|
||||||
match &op.expr {
|
|
||||||
Expr::Operator(operator) => match operator {
|
|
||||||
Operator::Plus => match (&lhs.ty, &rhs.ty) {
|
|
||||||
(Type::Int, Type::Int) => (Type::Int, None),
|
|
||||||
(Type::Unknown, _) => (Type::Unknown, None),
|
|
||||||
(_, Type::Unknown) => (Type::Unknown, None),
|
|
||||||
(Type::Int, _) => {
|
|
||||||
*rhs = Expression::garbage(rhs.span);
|
|
||||||
(
|
|
||||||
Type::Unknown,
|
|
||||||
Some(ParseError::Mismatch("int".into(), rhs.span)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
(_, Type::Int) => {
|
|
||||||
*lhs = Expression::garbage(lhs.span);
|
|
||||||
(
|
|
||||||
Type::Unknown,
|
|
||||||
Some(ParseError::Mismatch("int".into(), lhs.span)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
*op = Expression::garbage(op.span);
|
|
||||||
(
|
|
||||||
Type::Unknown,
|
|
||||||
Some(ParseError::Mismatch("math".into(), op.span)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
*op = Expression::garbage(op.span);
|
|
||||||
(
|
|
||||||
Type::Unknown,
|
|
||||||
Some(ParseError::Mismatch("math".into(), op.span)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
*op = Expression::garbage(op.span);
|
|
||||||
(
|
|
||||||
Type::Unknown,
|
|
||||||
Some(ParseError::Mismatch("operator".into(), op.span)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse_expression(&mut self, spans: &[Span]) -> (Expression, Option<ParseError>) {
|
pub fn parse_expression(&mut self, spans: &[Span]) -> (Expression, Option<ParseError>) {
|
||||||
let bytes = self.get_span_contents(spans[0]);
|
let bytes = self.get_span_contents(spans[0]);
|
||||||
|
|
||||||
match bytes[0] {
|
match bytes[0] {
|
||||||
b'0' | b'1' | b'2' | b'3' | b'4' | b'5' | b'6' | b'7' | b'8' | b'9' | b'(' | b'{'
|
b'0' | b'1' | b'2' | b'3' | b'4' | b'5' | b'6' | b'7' | b'8' | b'9' | b'(' | b'{'
|
||||||
| b'[' | b'$' => self.parse_math_expression(spans),
|
| b'[' | b'$' | b'"' | b'\'' => self.parse_math_expression(spans),
|
||||||
_ => self.parse_call(spans),
|
_ => self.parse_call(spans),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2166,7 +2125,7 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
|
|
||||||
self.add_file(fname.into(), contents);
|
self.add_file(fname.into(), contents);
|
||||||
|
|
||||||
let (output, err) = lex(&contents, span_offset, &[], &[]);
|
let (output, err) = lex(contents, span_offset, &[], &[]);
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
|
|
||||||
let (output, err) = lite_parse(&output);
|
let (output, err) = lite_parse(&output);
|
||||||
@ -2183,7 +2142,7 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
|
|
||||||
let span_offset = self.next_span_start();
|
let span_offset = self.next_span_start();
|
||||||
|
|
||||||
self.add_file("source".into(), source.into());
|
self.add_file("source".into(), source);
|
||||||
|
|
||||||
let (output, err) = lex(source, span_offset, &[], &[]);
|
let (output, err) = lex(source, span_offset, &[], &[]);
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
|
@ -347,9 +347,14 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_variable(&mut self, name: Vec<u8>, ty: Type) -> VarId {
|
pub fn add_variable(&mut self, mut name: Vec<u8>, ty: Type) -> VarId {
|
||||||
let next_id = self.next_var_id();
|
let next_id = self.next_var_id();
|
||||||
|
|
||||||
|
// correct name if necessary
|
||||||
|
if !name.starts_with(b"$") {
|
||||||
|
name.insert(0, b'$');
|
||||||
|
}
|
||||||
|
|
||||||
let last = self
|
let last = self
|
||||||
.delta
|
.delta
|
||||||
.scope
|
.scope
|
||||||
|
@ -203,21 +203,15 @@ impl Signature {
|
|||||||
let mut total = self.required_positional.len() + self.optional_positional.len();
|
let mut total = self.required_positional.len() + self.optional_positional.len();
|
||||||
|
|
||||||
for positional in &self.required_positional {
|
for positional in &self.required_positional {
|
||||||
match positional.shape {
|
if let SyntaxShape::Keyword(..) = positional.shape {
|
||||||
SyntaxShape::Keyword(..) => {
|
// Keywords have a required argument, so account for that
|
||||||
// Keywords have a required argument, so account for that
|
total += 1;
|
||||||
total += 1;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for positional in &self.optional_positional {
|
for positional in &self.optional_positional {
|
||||||
match positional.shape {
|
if let SyntaxShape::Keyword(..) = positional.shape {
|
||||||
SyntaxShape::Keyword(..) => {
|
// Keywords have a required argument, so account for that
|
||||||
// Keywords have a required argument, so account for that
|
total += 1;
|
||||||
total += 1;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
total
|
total
|
||||||
@ -285,10 +279,19 @@ impl Signature {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<Declaration> for Signature {
|
impl From<Box<Signature>> for Declaration {
|
||||||
fn into(self) -> Declaration {
|
fn from(val: Box<Signature>) -> Self {
|
||||||
Declaration {
|
Declaration {
|
||||||
signature: self,
|
signature: val,
|
||||||
|
body: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Signature> for Declaration {
|
||||||
|
fn from(val: Signature) -> Self {
|
||||||
|
Declaration {
|
||||||
|
signature: Box::new(val),
|
||||||
body: None,
|
body: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
49
src/type_check.rs
Normal file
49
src/type_check.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
use crate::{parser::Operator, parser_state::Type, Expr, Expression, ParseError, ParserWorkingSet};
|
||||||
|
|
||||||
|
impl<'a> ParserWorkingSet<'a> {
|
||||||
|
pub fn math_result_type(
|
||||||
|
&self,
|
||||||
|
lhs: &mut Expression,
|
||||||
|
op: &mut Expression,
|
||||||
|
rhs: &mut Expression,
|
||||||
|
) -> (Type, Option<ParseError>) {
|
||||||
|
match &op.expr {
|
||||||
|
Expr::Operator(operator) => match operator {
|
||||||
|
Operator::Plus => match (&lhs.ty, &rhs.ty) {
|
||||||
|
(Type::Int, Type::Int) => (Type::Int, None),
|
||||||
|
(Type::String, Type::String) => (Type::String, None),
|
||||||
|
(Type::Unknown, _) => (Type::Unknown, None),
|
||||||
|
(_, Type::Unknown) => (Type::Unknown, None),
|
||||||
|
(Type::Int, _) => {
|
||||||
|
*rhs = Expression::garbage(rhs.span);
|
||||||
|
(
|
||||||
|
Type::Unknown,
|
||||||
|
Some(ParseError::Mismatch("int".into(), rhs.span)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
*op = Expression::garbage(op.span);
|
||||||
|
(
|
||||||
|
Type::Unknown,
|
||||||
|
Some(ParseError::Mismatch("math".into(), op.span)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
*op = Expression::garbage(op.span);
|
||||||
|
(
|
||||||
|
Type::Unknown,
|
||||||
|
Some(ParseError::Mismatch("math".into(), op.span)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
*op = Expression::garbage(op.span);
|
||||||
|
(
|
||||||
|
Type::Unknown,
|
||||||
|
Some(ParseError::Mismatch("operator".into(), op.span)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user