Improve call eval and live check

This commit is contained in:
JT 2021-07-24 09:19:30 +12:00
parent 3eefa6dec8
commit 6fcdc76059
7 changed files with 352 additions and 85 deletions

View file

@ -1,6 +1,8 @@
use std::collections::HashMap; use std::collections::HashMap;
use crate::{parser::Operator, Block, Call, Expr, Expression, ParserState, Span, Statement, VarId}; use crate::{
parser::Operator, Block, BlockId, Call, Expr, Expression, ParserState, Span, Statement, VarId,
};
#[derive(Debug)] #[derive(Debug)]
pub enum ShellError { pub enum ShellError {
@ -12,6 +14,9 @@ pub enum ShellError {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Value { pub enum Value {
Int { val: i64, span: Span }, Int { val: i64, span: Span },
String { val: String, span: Span },
List(Vec<Value>),
Block(BlockId),
Unknown, Unknown,
} }
impl Value { impl Value {
@ -38,14 +43,21 @@ impl Stack {
pub fn get_var(&self, var_id: VarId) -> Result<Value, ShellError> { pub fn get_var(&self, var_id: VarId) -> Result<Value, ShellError> {
match self.vars.get(&var_id) { match self.vars.get(&var_id) {
Some(v) => Ok(v.clone()), Some(v) => Ok(v.clone()),
_ => Err(ShellError::InternalError("variable not found".into())), _ => {
println!("var_id: {}", var_id);
Err(ShellError::InternalError("variable not found".into()))
}
} }
} }
pub fn add_var(&mut self, var_id: VarId, value: Value) {
self.vars.insert(var_id, value);
}
} }
pub fn eval_operator( pub fn eval_operator(
state: &State, _state: &State,
stack: &mut Stack, _stack: &mut Stack,
op: &Expression, op: &Expression,
) -> Result<Operator, ShellError> { ) -> Result<Operator, ShellError> {
match op { match op {
@ -59,8 +71,19 @@ pub fn eval_operator(
fn eval_call(state: &State, stack: &mut Stack, call: &Call) -> Result<Value, ShellError> { fn eval_call(state: &State, stack: &mut Stack, call: &Call) -> Result<Value, ShellError> {
let decl = state.parser_state.get_decl(call.decl_id); let decl = state.parser_state.get_decl(call.decl_id);
if let Some(block_id) = decl.body { if let Some(block_id) = decl.body {
for (arg, param) in call
.positional
.iter()
.zip(decl.signature.required_positional.iter())
{
let result = eval_expression(state, stack, arg)?;
let var_id = param
.var_id
.expect("internal error: all custom parameters must have var_ids");
stack.add_var(var_id, result);
}
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 {
@ -98,13 +121,22 @@ pub fn eval_expression(
eval_block(state, stack, block) eval_block(state, stack, block)
} }
Expr::Block(_) => Err(ShellError::Unsupported(expr.span)), Expr::Block(block_id) => Ok(Value::Block(*block_id)),
Expr::List(_) => Err(ShellError::Unsupported(expr.span)), Expr::List(x) => {
let mut output = vec![];
for expr in x {
output.push(eval_expression(state, stack, expr)?);
}
Ok(Value::List(output))
}
Expr::Table(_, _) => Err(ShellError::Unsupported(expr.span)), Expr::Table(_, _) => Err(ShellError::Unsupported(expr.span)),
Expr::Literal(_) => Err(ShellError::Unsupported(expr.span)), Expr::Literal(_) => Ok(Value::Unknown),
Expr::String(_) => Err(ShellError::Unsupported(expr.span)), Expr::String(s) => Ok(Value::String {
Expr::Signature(_) => Err(ShellError::Unsupported(expr.span)), val: s.clone(),
Expr::Garbage => Err(ShellError::Unsupported(expr.span)), span: expr.span,
}),
Expr::Signature(_) => Ok(Value::Unknown),
Expr::Garbage => Ok(Value::Unknown),
} }
} }

View file

@ -26,6 +26,7 @@ impl<'a> ParserWorkingSet<'a> {
match stmt { match stmt {
Statement::Expression(expr) => self.flatten_expression(expr), Statement::Expression(expr) => self.flatten_expression(expr),
Statement::Pipeline(pipeline) => self.flatten_pipeline(pipeline), Statement::Pipeline(pipeline) => self.flatten_pipeline(pipeline),
_ => vec![],
} }
} }

View file

@ -65,6 +65,14 @@ fn main() -> std::io::Result<()> {
// .named("--jazz", SyntaxShape::Int, "jazz!!", Some('j')) // .named("--jazz", SyntaxShape::Int, "jazz!!", Some('j'))
// .switch("--rock", "rock!!", Some('r')); // .switch("--rock", "rock!!", Some('r'));
// working_set.add_decl(sig.into()); // working_set.add_decl(sig.into());
let sig = Signature::build("exit");
working_set.add_decl(sig.into());
let sig = Signature::build("vars");
working_set.add_decl(sig.into());
let sig = Signature::build("decls");
working_set.add_decl(sig.into());
let sig = Signature::build("blocks");
working_set.add_decl(sig.into());
let sig = Signature::build("add"); let sig = Signature::build("add");
working_set.add_decl(sig.into()); working_set.add_decl(sig.into());
@ -89,7 +97,7 @@ fn main() -> std::io::Result<()> {
let file = std::fs::read(&path)?; let file = std::fs::read(&path)?;
let (block, err) = working_set.parse_file(&path, &file, false); let (block, _err) = working_set.parse_file(&path, &file, false);
println!("{}", block.len()); println!("{}", block.len());
// println!("{:#?}", output); // println!("{:#?}", output);
// println!("error: {:?}", err); // println!("error: {:?}", err);
@ -130,6 +138,15 @@ fn main() -> std::io::Result<()> {
Signal::Success(s) => { Signal::Success(s) => {
if s.trim() == "exit" { if s.trim() == "exit" {
break; break;
} else if s.trim() == "vars" {
parser_state.borrow().print_vars();
continue;
} else if s.trim() == "decls" {
parser_state.borrow().print_decls();
continue;
} else if s.trim() == "blocks" {
parser_state.borrow().print_blocks();
continue;
} }
// println!("input: '{}'", s); // println!("input: '{}'", s);

View file

@ -13,6 +13,7 @@ pub enum ParseError {
UnknownCommand(Span), UnknownCommand(Span),
NonUtf8(Span), NonUtf8(Span),
UnknownFlag(Span), UnknownFlag(Span),
UnknownType(Span),
MissingFlagParam(Span), MissingFlagParam(Span),
ShortFlagBatchCantTakeArg(Span), ShortFlagBatchCantTakeArg(Span),
MissingPositional(String, Span), MissingPositional(String, Span),

View file

@ -78,6 +78,38 @@ pub enum SyntaxShape {
Expression, Expression,
} }
impl SyntaxShape {
pub fn to_type(&self) -> Type {
match self {
SyntaxShape::Any => Type::Unknown,
SyntaxShape::Block => Type::Block,
SyntaxShape::ColumnPath => Type::Unknown,
SyntaxShape::Duration => Type::Duration,
SyntaxShape::Expression => Type::Unknown,
SyntaxShape::FilePath => Type::FilePath,
SyntaxShape::Filesize => Type::Filesize,
SyntaxShape::FullColumnPath => Type::Unknown,
SyntaxShape::GlobPattern => Type::String,
SyntaxShape::Int => Type::Int,
SyntaxShape::List(x) => {
let contents = x.to_type();
Type::List(Box::new(contents))
}
SyntaxShape::Literal(..) => Type::Unknown,
SyntaxShape::MathExpression => Type::Unknown,
SyntaxShape::Number => Type::Number,
SyntaxShape::Operator => Type::Unknown,
SyntaxShape::Range => Type::Unknown,
SyntaxShape::RowCondition => Type::Bool,
SyntaxShape::Signature => Type::Unknown,
SyntaxShape::String => Type::String,
SyntaxShape::Table => Type::Table,
SyntaxShape::VarWithOptType => Type::Unknown,
SyntaxShape::Variable => Type::Unknown,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum Operator { pub enum Operator {
Equal, Equal,
@ -148,13 +180,14 @@ pub enum Expr {
pub struct Expression { pub struct Expression {
pub expr: Expr, pub expr: Expr,
pub span: Span, pub span: Span,
pub ty: Type,
} }
impl Expression { impl Expression {
pub fn garbage(span: Span) -> Expression { pub fn garbage(span: Span) -> Expression {
Expression { Expression {
expr: Expr::Garbage, expr: Expr::Garbage,
span, span,
//ty: Type::Unknown, ty: Type::Unknown,
} }
} }
pub fn precedence(&self) -> usize { pub fn precedence(&self) -> usize {
@ -272,6 +305,7 @@ pub struct VarDecl {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Statement { pub enum Statement {
Declaration(DeclId),
Pipeline(Pipeline), Pipeline(Pipeline),
Expression(Expression), Expression(Expression),
} }
@ -359,6 +393,7 @@ impl<'a> ParserWorkingSet<'a> {
Expression { Expression {
expr: Expr::ExternalCall(name, args), expr: Expr::ExternalCall(name, args),
span: span(spans), span: span(spans),
ty: Type::Unknown,
}, },
None, None,
) )
@ -533,6 +568,7 @@ impl<'a> ParserWorkingSet<'a> {
Expression { Expression {
expr: Expr::Literal(literal), expr: Expr::Literal(literal),
span: arg_span, span: arg_span,
ty: Type::Unknown,
}, },
error, error,
) )
@ -678,6 +714,7 @@ impl<'a> ParserWorkingSet<'a> {
Expression { Expression {
expr: Expr::Call(call), expr: Expr::Call(call),
span: span(spans), span: span(spans),
ty: Type::Unknown, // FIXME
}, },
err, err,
) )
@ -693,6 +730,7 @@ impl<'a> ParserWorkingSet<'a> {
Expression { Expression {
expr: Expr::Int(v), expr: Expr::Int(v),
span, span,
ty: Type::Int,
}, },
None, None,
) )
@ -708,6 +746,7 @@ impl<'a> ParserWorkingSet<'a> {
Expression { Expression {
expr: Expr::Int(v), expr: Expr::Int(v),
span, span,
ty: Type::Int,
}, },
None, None,
) )
@ -723,6 +762,7 @@ impl<'a> ParserWorkingSet<'a> {
Expression { Expression {
expr: Expr::Int(v), expr: Expr::Int(v),
span, span,
ty: Type::Int,
}, },
None, None,
) )
@ -737,6 +777,7 @@ impl<'a> ParserWorkingSet<'a> {
Expression { Expression {
expr: Expr::Int(x), expr: Expr::Int(x),
span, span,
ty: Type::Int,
}, },
None, None,
) )
@ -767,6 +808,7 @@ impl<'a> ParserWorkingSet<'a> {
Expression { Expression {
expr: Expr::Var(var_id), expr: Expr::Var(var_id),
span, span,
ty: self.get_variable(var_id).clone(),
}, },
None, None,
) )
@ -784,6 +826,7 @@ impl<'a> ParserWorkingSet<'a> {
Expression { Expression {
expr: Expr::Var(id), expr: Expr::Var(id),
span, span,
ty: self.get_variable(id).clone(),
}, },
None, None,
) )
@ -796,6 +839,7 @@ impl<'a> ParserWorkingSet<'a> {
Expression { Expression {
expr: Expr::Var(id), expr: Expr::Var(id),
span, span,
ty: Type::Unknown,
}, },
None, None,
) )
@ -849,6 +893,7 @@ impl<'a> ParserWorkingSet<'a> {
Expression { Expression {
expr: Expr::Subexpression(block_id), expr: Expr::Subexpression(block_id),
span, span,
ty: Type::Unknown, // FIXME
}, },
error, error,
) )
@ -862,6 +907,7 @@ impl<'a> ParserWorkingSet<'a> {
Expression { Expression {
expr: Expr::String(token), expr: Expr::String(token),
span, span,
ty: Type::String,
}, },
None, None,
) )
@ -874,8 +920,8 @@ impl<'a> ParserWorkingSet<'a> {
} }
//TODO: Handle error case //TODO: Handle error case
pub fn parse_shape_name(&self, bytes: &[u8]) -> SyntaxShape { pub fn parse_shape_name(&self, bytes: &[u8], span: Span) -> (SyntaxShape, Option<ParseError>) {
match bytes { let result = match bytes {
b"any" => SyntaxShape::Any, b"any" => SyntaxShape::Any,
b"string" => SyntaxShape::String, b"string" => SyntaxShape::String,
b"column-path" => SyntaxShape::ColumnPath, b"column-path" => SyntaxShape::ColumnPath,
@ -891,8 +937,10 @@ impl<'a> ParserWorkingSet<'a> {
b"variable" => SyntaxShape::Variable, b"variable" => SyntaxShape::Variable,
b"signature" => SyntaxShape::Signature, b"signature" => SyntaxShape::Signature,
b"expr" => SyntaxShape::Expression, b"expr" => SyntaxShape::Expression,
_ => SyntaxShape::Any, _ => return (SyntaxShape::Any, Some(ParseError::UnknownType(span))),
} };
(result, None)
} }
pub fn parse_type(&self, bytes: &[u8]) -> Type { pub fn parse_type(&self, bytes: &[u8]) -> Type {
@ -919,12 +967,13 @@ impl<'a> ParserWorkingSet<'a> {
let ty = self.parse_type(type_bytes); let ty = self.parse_type(type_bytes);
*spans_idx += 1; *spans_idx += 1;
let id = self.add_variable(bytes[0..(bytes.len() - 1)].to_vec(), ty); let id = self.add_variable(bytes[0..(bytes.len() - 1)].to_vec(), ty.clone());
( (
Expression { Expression {
expr: Expr::Var(id), expr: Expr::Var(id),
span: span(&spans[*spans_idx - 2..*spans_idx]), span: span(&spans[*spans_idx - 2..*spans_idx]),
ty,
}, },
None, None,
) )
@ -935,6 +984,7 @@ impl<'a> ParserWorkingSet<'a> {
Expression { Expression {
expr: Expr::Var(id), expr: Expr::Var(id),
span: spans[*spans_idx], span: spans[*spans_idx],
ty: Type::Unknown,
}, },
Some(ParseError::MissingType(spans[*spans_idx])), Some(ParseError::MissingType(spans[*spans_idx])),
) )
@ -947,6 +997,7 @@ impl<'a> ParserWorkingSet<'a> {
Expression { Expression {
expr: Expr::Var(id), expr: Expr::Var(id),
span: span(&spans[*spans_idx - 1..*spans_idx]), span: span(&spans[*spans_idx - 1..*spans_idx]),
ty: Type::Unknown,
}, },
None, None,
) )
@ -1023,18 +1074,26 @@ impl<'a> ParserWorkingSet<'a> {
ParseMode::ArgMode => { ParseMode::ArgMode => {
if contents.starts_with(b"--") && contents.len() > 2 { if contents.starts_with(b"--") && contents.len() > 2 {
// Long flag // Long flag
let flags: Vec<_> = contents.split(|x| x == &b'(').collect(); let flags: Vec<_> = contents
.split(|x| x == &b'(')
.map(|x| x.to_vec())
.collect();
let long = String::from_utf8_lossy(&flags[0]).to_string();
let variable_name = flags[0][2..].to_vec();
let var_id = self.add_variable(variable_name, Type::Unknown);
if flags.len() == 1 { if flags.len() == 1 {
args.push(Arg::Flag(Flag { args.push(Arg::Flag(Flag {
arg: None, arg: None,
desc: String::new(), desc: String::new(),
long: String::from_utf8_lossy(flags[0]).to_string(), long,
short: None, short: None,
required: false, required: false,
var_id: Some(var_id),
})); }));
} else { } else {
let short_flag = flags[1]; let short_flag = &flags[1];
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")")
{ {
@ -1048,16 +1107,21 @@ impl<'a> ParserWorkingSet<'a> {
}; };
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 variable_name = flags[0][2..].to_vec();
let var_id =
self.add_variable(variable_name, Type::Unknown);
if chars.len() == 1 { if chars.len() == 1 {
args.push(Arg::Flag(Flag { args.push(Arg::Flag(Flag {
arg: None, arg: None,
desc: String::new(), desc: String::new(),
long: String::from_utf8_lossy(flags[0]).to_string(), long,
short: Some(chars[0]), short: Some(chars[0]),
required: false, required: false,
var_id: Some(var_id),
})); }));
} else { } else {
error = error.or(Some(ParseError::Mismatch( error = error.or(Some(ParseError::Mismatch(
@ -1086,14 +1150,22 @@ impl<'a> ParserWorkingSet<'a> {
long: String::new(), long: String::new(),
short: None, short: None,
required: false, required: false,
var_id: None,
})); }));
} else { } else {
let mut encoded_var_name = vec![0u8; 4];
let len = chars[0].encode_utf8(&mut encoded_var_name).len();
let variable_name = encoded_var_name[0..len].to_vec();
let var_id =
self.add_variable(variable_name, Type::Unknown);
args.push(Arg::Flag(Flag { args.push(Arg::Flag(Flag {
arg: None, arg: None,
desc: String::new(), desc: String::new(),
long: String::new(), long: String::new(),
short: Some(chars[0]), short: Some(chars[0]),
required: false, required: false,
var_id: Some(var_id),
})); }));
} }
} else if contents.starts_with(b"(-") { } else if contents.starts_with(b"(-") {
@ -1140,24 +1212,35 @@ impl<'a> ParserWorkingSet<'a> {
} }
} else { } else {
if contents.ends_with(b"?") { if contents.ends_with(b"?") {
let contents = &contents[..(contents.len() - 1)]; let contents: Vec<_> =
contents[..(contents.len() - 1)].into();
let name = String::from_utf8_lossy(&contents).to_string();
let var_id =
self.add_variable(contents.into(), Type::Unknown);
// Positional arg, optional // Positional arg, optional
args.push(Arg::Positional( args.push(Arg::Positional(
PositionalArg { PositionalArg {
desc: String::new(), desc: String::new(),
name: String::from_utf8_lossy(contents).to_string(), name,
shape: SyntaxShape::Any, shape: SyntaxShape::Any,
var_id: Some(var_id),
}, },
false, false,
)) ))
} else { } 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 // Positional arg, required
args.push(Arg::Positional( args.push(Arg::Positional(
PositionalArg { PositionalArg {
desc: String::new(), desc: String::new(),
name: String::from_utf8_lossy(contents).to_string(), name,
shape: SyntaxShape::Any, shape: SyntaxShape::Any,
var_id: Some(var_id),
}, },
true, true,
)) ))
@ -1166,13 +1249,21 @@ impl<'a> ParserWorkingSet<'a> {
} }
ParseMode::TypeMode => { ParseMode::TypeMode => {
if let Some(last) = args.last_mut() { if let Some(last) = args.last_mut() {
let syntax_shape = self.parse_shape_name(contents); let (syntax_shape, err) = self.parse_shape_name(contents, span);
error = error.or(err);
//TODO check if we're replacing one already //TODO check if we're replacing one already
match last { match last {
Arg::Positional(PositionalArg { shape, .. }, ..) => { Arg::Positional(
PositionalArg { shape, var_id, .. },
..,
) => {
self.set_variable_type(var_id.expect("internal error: all custom parameters must have var_ids"), syntax_shape.to_type());
*shape = syntax_shape; *shape = syntax_shape;
} }
Arg::Flag(Flag { arg, .. }) => *arg = Some(syntax_shape), Arg::Flag(Flag { arg, var_id, .. }) => {
self.set_variable_type(var_id.expect("internal error: all custom parameters must have var_ids"), syntax_shape.to_type());
*arg = Some(syntax_shape)
}
} }
} }
parse_mode = ParseMode::ArgMode; parse_mode = ParseMode::ArgMode;
@ -1242,6 +1333,7 @@ impl<'a> ParserWorkingSet<'a> {
Expression { Expression {
expr: Expr::Signature(sig), expr: Expr::Signature(sig),
span, span,
ty: Type::Unknown,
}, },
error, error,
) )
@ -1310,6 +1402,7 @@ impl<'a> ParserWorkingSet<'a> {
Expression { Expression {
expr: Expr::List(args), expr: Expr::List(args),
span, span,
ty: Type::List(Box::new(Type::Unknown)), // FIXME
}, },
error, error,
) )
@ -1354,6 +1447,7 @@ impl<'a> ParserWorkingSet<'a> {
Expression { Expression {
expr: Expr::List(vec![]), expr: Expr::List(vec![]),
span, span,
ty: Type::Table,
}, },
None, None,
), ),
@ -1393,6 +1487,7 @@ impl<'a> ParserWorkingSet<'a> {
Expression { Expression {
expr: Expr::Table(table_headers, rows), expr: Expr::Table(table_headers, rows),
span, span,
ty: Type::Table,
}, },
error, error,
) )
@ -1448,6 +1543,7 @@ impl<'a> ParserWorkingSet<'a> {
Expression { Expression {
expr: Expr::Block(block_id), expr: Expr::Block(block_id),
span, span,
ty: Type::Block,
}, },
error, error,
) )
@ -1514,6 +1610,7 @@ impl<'a> ParserWorkingSet<'a> {
Expression { Expression {
expr: Expr::Literal(literal), expr: Expr::Literal(literal),
span, span,
ty: Type::Unknown,
}, },
None, None,
) )
@ -1633,6 +1730,7 @@ impl<'a> ParserWorkingSet<'a> {
Expression { Expression {
expr: Expr::Operator(operator), expr: Expr::Operator(operator),
span, span,
ty: Type::Unknown,
}, },
None, None,
) )
@ -1686,20 +1784,24 @@ impl<'a> ParserWorkingSet<'a> {
while expr_stack.len() > 1 { while expr_stack.len() > 1 {
// Collapse the right associated operations first // Collapse the right associated operations first
// so that we can get back to a stack with a lower precedence // so that we can get back to a stack with a lower precedence
let rhs = expr_stack let mut rhs = expr_stack
.pop() .pop()
.expect("internal error: expression stack empty"); .expect("internal error: expression stack empty");
let op = expr_stack let mut op = expr_stack
.pop() .pop()
.expect("internal error: expression stack empty"); .expect("internal error: expression stack empty");
let lhs = expr_stack let mut lhs = expr_stack
.pop() .pop()
.expect("internal error: expression stack empty"); .expect("internal error: expression stack empty");
let (result_ty, err) = self.math_result_type(&mut lhs, &mut op, &mut rhs);
error = error.or(err);
let op_span = span(&[lhs.span, rhs.span]); let op_span = span(&[lhs.span, rhs.span]);
expr_stack.push(Expression { expr_stack.push(Expression {
expr: Expr::BinaryOp(Box::new(lhs), Box::new(op), Box::new(rhs)), expr: Expr::BinaryOp(Box::new(lhs), Box::new(op), Box::new(rhs)),
span: op_span, span: op_span,
ty: result_ty,
}); });
} }
} }
@ -1712,20 +1814,24 @@ impl<'a> ParserWorkingSet<'a> {
} }
while expr_stack.len() != 1 { while expr_stack.len() != 1 {
let rhs = expr_stack let mut rhs = expr_stack
.pop() .pop()
.expect("internal error: expression stack empty"); .expect("internal error: expression stack empty");
let op = expr_stack let mut op = expr_stack
.pop() .pop()
.expect("internal error: expression stack empty"); .expect("internal error: expression stack empty");
let lhs = expr_stack let mut lhs = expr_stack
.pop() .pop()
.expect("internal error: expression stack empty"); .expect("internal error: expression stack empty");
let (result_ty, err) = self.math_result_type(&mut lhs, &mut op, &mut rhs);
error = error.or(err);
let binary_op_span = span(&[lhs.span, rhs.span]); let binary_op_span = span(&[lhs.span, rhs.span]);
expr_stack.push(Expression { expr_stack.push(Expression {
expr: Expr::BinaryOp(Box::new(lhs), Box::new(op), Box::new(rhs)), expr: Expr::BinaryOp(Box::new(lhs), Box::new(op), Box::new(rhs)),
span: binary_op_span, span: binary_op_span,
ty: result_ty,
}); });
} }
@ -1736,6 +1842,58 @@ 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]);
@ -1772,60 +1930,69 @@ impl<'a> ParserWorkingSet<'a> {
} }
pub fn parse_def(&mut self, spans: &[Span]) -> (Statement, Option<ParseError>) { pub fn parse_def(&mut self, spans: &[Span]) -> (Statement, Option<ParseError>) {
let mut error = None;
let name = self.get_span_contents(spans[0]); let name = self.get_span_contents(spans[0]);
if name == b"def" { if name == b"def" && spans.len() >= 4 {
if let Some(decl_id) = self.find_decl(b"def") { //FIXME: don't use expect here
let (call, call_span, err) = let (name_expr, err) = self.parse_string(spans[1]);
self.parse_internal_call(spans[0], &spans[1..], decl_id); let name = name_expr
.as_string()
.expect("internal error: expected def name");
error = error.or(err);
if err.is_some() { self.enter_scope();
return ( let (sig, err) = self.parse_signature(spans[2]);
Statement::Expression(Expression { let mut signature = sig
expr: Expr::Call(call), .as_signature()
span: call_span, .expect("internal error: expected param list");
}), error = error.or(err);
err,
);
} else {
let name = call.positional[0]
.as_string()
.expect("internal error: expected def name");
let mut signature = call.positional[1]
.as_signature()
.expect("internal error: expected param list");
let block_id = call.positional[2]
.as_block()
.expect("internal error: expected block");
signature.name = name; let (block, err) = self.parse_block_expression(spans[3]);
let decl = Declaration { self.exit_scope();
signature,
body: Some(block_id),
};
self.add_decl(decl); let block_id = block.as_block().expect("internal error: expected block");
error = error.or(err);
return ( signature.name = name;
Statement::Expression(Expression { let decl = Declaration {
expr: Expr::Call(call), signature,
span: call_span, body: Some(block_id),
}), };
None,
); self.add_decl(decl);
} let def_decl_id = self
} .find_decl(b"def")
.expect("internal error: missing def command");
let call = Box::new(Call {
head: spans[0],
decl_id: def_decl_id,
positional: vec![name_expr, sig, block],
named: vec![],
});
(
Statement::Expression(Expression {
expr: Expr::Call(call),
span: span(spans),
ty: Type::Unknown,
}),
error,
)
} else {
(
Statement::Expression(Expression {
expr: Expr::Garbage,
span: span(spans),
ty: Type::Unknown,
}),
Some(ParseError::UnknownState(
"internal error: let statement unparseable".into(),
span(spans),
)),
)
} }
(
Statement::Expression(Expression {
expr: Expr::Garbage,
span: span(spans),
}),
Some(ParseError::UnknownState(
"internal error: let statement unparseable".into(),
span(spans),
)),
)
} }
pub fn parse_let(&mut self, spans: &[Span]) -> (Statement, Option<ParseError>) { pub fn parse_let(&mut self, spans: &[Span]) -> (Statement, Option<ParseError>) {
@ -1840,6 +2007,7 @@ impl<'a> ParserWorkingSet<'a> {
Statement::Expression(Expression { Statement::Expression(Expression {
expr: Expr::Call(call), expr: Expr::Call(call),
span: call_span, span: call_span,
ty: Type::Unknown,
}), }),
err, err,
); );
@ -1849,6 +2017,7 @@ impl<'a> ParserWorkingSet<'a> {
Statement::Expression(Expression { Statement::Expression(Expression {
expr: Expr::Garbage, expr: Expr::Garbage,
span: span(spans), span: span(spans),
ty: Type::Unknown,
}), }),
Some(ParseError::UnknownState( Some(ParseError::UnknownState(
"internal error: let statement unparseable".into(), "internal error: let statement unparseable".into(),

View file

@ -1,4 +1,5 @@
use crate::{parser::Block, Declaration, Span}; use crate::{parser::Block, Declaration, Span};
use core::panic;
use std::collections::HashMap; use std::collections::HashMap;
#[derive(Debug)] #[derive(Debug)]
@ -11,9 +12,19 @@ pub struct ParserState {
scope: Vec<ScopeFrame>, scope: Vec<ScopeFrame>,
} }
#[derive(Clone, Copy, Debug)] #[derive(Clone, Debug)]
pub enum Type { pub enum Type {
Int, Int,
Bool,
String,
Block,
ColumnPath,
Duration,
FilePath,
Filesize,
List(Box<Type>),
Number,
Table,
Unknown, Unknown,
} }
@ -89,6 +100,24 @@ impl ParserState {
self.blocks.len() self.blocks.len()
} }
pub fn print_vars(&self) {
for var in self.vars.iter().enumerate() {
println!("var{}: {:?}", var.0, var.1);
}
}
pub fn print_decls(&self) {
for decl in self.decls.iter().enumerate() {
println!("decl{}: {:?}", decl.0, decl.1);
}
}
pub fn print_blocks(&self) {
for block in self.blocks.iter().enumerate() {
println!("block{}: {:?}", block.0, block.1);
}
}
pub fn get_var(&self, var_id: VarId) -> &Type { pub fn get_var(&self, var_id: VarId) -> &Type {
self.vars self.vars
.get(var_id) .get(var_id)
@ -319,11 +348,20 @@ impl<'a> ParserWorkingSet<'a> {
last.vars.insert(name, next_id); last.vars.insert(name, next_id);
self.delta.vars.insert(next_id, ty); self.delta.vars.push(ty);
next_id next_id
} }
pub fn set_variable_type(&mut self, var_id: VarId, ty: Type) {
let num_permanent_vars = self.permanent_state.num_vars();
if var_id < num_permanent_vars {
panic!("Internal error: attempted to set into permanent state from working set")
} else {
self.delta.vars[var_id - num_permanent_vars] = ty;
}
}
pub fn get_variable(&self, var_id: VarId) -> &Type { pub fn get_variable(&self, var_id: VarId) -> &Type {
let num_permanent_vars = self.permanent_state.num_vars(); let num_permanent_vars = self.permanent_state.num_vars();
if var_id < num_permanent_vars { if var_id < num_permanent_vars {

View file

@ -1,4 +1,4 @@
use crate::{parser::SyntaxShape, Declaration}; use crate::{parser::SyntaxShape, Declaration, VarId};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Flag { pub struct Flag {
@ -7,6 +7,8 @@ pub struct Flag {
pub arg: Option<SyntaxShape>, pub arg: Option<SyntaxShape>,
pub required: bool, pub required: bool,
pub desc: String, pub desc: String,
// For custom commands
pub var_id: Option<VarId>,
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
@ -14,6 +16,8 @@ pub struct PositionalArg {
pub name: String, pub name: String,
pub desc: String, pub desc: String,
pub shape: SyntaxShape, pub shape: SyntaxShape,
// For custom commands
pub var_id: Option<VarId>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -75,6 +79,7 @@ impl Signature {
name: name.into(), name: name.into(),
desc: desc.into(), desc: desc.into(),
shape: shape.into(), shape: shape.into(),
var_id: None,
}); });
self self
@ -91,6 +96,7 @@ impl Signature {
name: name.into(), name: name.into(),
desc: desc.into(), desc: desc.into(),
shape: shape.into(), shape: shape.into(),
var_id: None,
}); });
self self
@ -114,6 +120,7 @@ impl Signature {
arg: Some(shape.into()), arg: Some(shape.into()),
required: false, required: false,
desc: desc.into(), desc: desc.into(),
var_id: None,
}); });
self self
@ -137,6 +144,7 @@ impl Signature {
arg: Some(shape.into()), arg: Some(shape.into()),
required: true, required: true,
desc: desc.into(), desc: desc.into(),
var_id: None,
}); });
self self
@ -163,6 +171,7 @@ impl Signature {
arg: None, arg: None,
required: false, required: false,
desc: desc.into(), desc: desc.into(),
var_id: None,
}); });
self self
} }