fix clippy, add strings and concat

This commit is contained in:
JT 2021-07-30 10:56:51 +12:00
parent a8366ebf15
commit 2eeceae613
11 changed files with 253 additions and 231 deletions

View File

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

View File

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

View File

@ -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)?);
}
_ => {}
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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