fix(argus): correctly handle untyped vars and recursion

This commit is contained in:
Anand Balakrishnan 2023-10-12 16:28:22 -07:00
parent 3880356c66
commit c68620dfdd
No known key found for this signature in database
3 changed files with 51 additions and 21 deletions

View file

@ -139,8 +139,8 @@ pub fn lexer<'src>() -> impl Parser<'src, &'src str, Output<'src>, Error<'src>>
just("&&").to(Token::And), just("&&").to(Token::And),
just("&").to(Token::And), just("&").to(Token::And),
just("\u{2227}").to(Token::And), // ∧ just("\u{2227}").to(Token::And), // ∧
just("||").to(Token::And), just("||").to(Token::Or),
just("|").to(Token::And), just("|").to(Token::Or),
just("\u{2228}").to(Token::Or), // just("\u{2228}").to(Token::Or), //
just("^").to(Token::Xor), just("^").to(Token::Xor),
just("-").to(Token::Minus), just("-").to(Token::Minus),

View file

@ -7,6 +7,7 @@ mod lexer;
mod syntax; mod syntax;
use chumsky::prelude::Rich; use chumsky::prelude::Rich;
use itertools::Itertools;
use lexer::{lexer, Token}; use lexer::{lexer, Token};
use syntax::{parser, Expr, Interval}; use syntax::{parser, Expr, Interval};
@ -17,6 +18,10 @@ pub fn parse_str(src: &str) -> Result<crate::core::expr::Expr, Vec<Rich<'_, Stri
use chumsky::prelude::{Input, Parser}; use chumsky::prelude::{Input, Parser};
let (tokens, lex_errors) = lexer().parse(src).into_output_errors(); let (tokens, lex_errors) = lexer().parse(src).into_output_errors();
log::debug!("** Tokens output **");
log::debug!("{:#?}", tokens);
log::debug!("** Lexing Errors **");
log::debug!("[{}]", lex_errors.iter().map(|e| e.to_string()).join("\n- "));
let (parsed, parse_errors) = if let Some(tokens) = &tokens { let (parsed, parse_errors) = if let Some(tokens) = &tokens {
parser() parser()
@ -26,6 +31,11 @@ pub fn parse_str(src: &str) -> Result<crate::core::expr::Expr, Vec<Rich<'_, Stri
(None, Vec::new()) (None, Vec::new())
}; };
log::debug!("** Parse output **");
log::debug!("{:#?}", parsed);
log::debug!("** Parse Errors **");
log::debug!("[{}]", parse_errors.iter().map(|e| e.to_string()).join("\n- "));
let (expr, expr_errors) = if let Some((ast, span)) = parsed { let (expr, expr_errors) = if let Some((ast, span)) = parsed {
let mut expr_builder = ExprBuilder::new(); let mut expr_builder = ExprBuilder::new();
let result = ast_to_expr(&ast, span, &mut expr_builder); let result = ast_to_expr(&ast, span, &mut expr_builder);
@ -37,6 +47,11 @@ pub fn parse_str(src: &str) -> Result<crate::core::expr::Expr, Vec<Rich<'_, Stri
(None, vec![]) (None, vec![])
}; };
log::debug!("** Final Expression **");
log::debug!("{:#?}", expr);
log::debug!("** AST to Expr Errors **");
log::debug!("[{}]", expr_errors.iter().map(|e| e.to_string()).join("\n- "));
let errors: Vec<_> = lex_errors let errors: Vec<_> = lex_errors
.into_iter() .into_iter()
.map(|e| e.map_token(|c| c.to_string())) .map(|e| e.map_token(|c| c.to_string()))

View file

@ -21,12 +21,21 @@ pub enum UnaryOps {
} }
impl UnaryOps { impl UnaryOps {
/// Get the default type for the *arguments* of this kind of expression.
fn default_args_type(&self) -> Type { fn default_args_type(&self) -> Type {
match self { match self {
UnaryOps::Neg => Type::Float, UnaryOps::Neg => Type::Float,
_ => Type::Bool, _ => Type::Bool,
} }
} }
/// Get the default type the expression with this operator should be
fn get_default_type(&self) -> Type {
match self {
UnaryOps::Neg => Type::Float,
_ => Type::Bool,
}
}
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@ -50,6 +59,7 @@ pub enum BinaryOps {
} }
impl BinaryOps { impl BinaryOps {
/// Get the default type for the *arguments* of this kind of expression.
fn default_args_type(&self) -> Type { fn default_args_type(&self) -> Type {
match self { match self {
BinaryOps::Add BinaryOps::Add
@ -65,6 +75,14 @@ impl BinaryOps {
_ => Type::Bool, _ => Type::Bool,
} }
} }
/// Get the default type the expression with this operator should be
fn get_default_type(&self) -> Type {
match self {
BinaryOps::Add | BinaryOps::Sub | BinaryOps::Mul | BinaryOps::Div => Type::Float,
_ => Type::Bool,
}
}
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -103,12 +121,12 @@ impl<'src> Expr<'src> {
op, op,
interval: _, interval: _,
arg: _, arg: _,
} => op.default_args_type(), } => op.get_default_type(),
Expr::Binary { Expr::Binary {
op, op,
interval: _, interval: _,
args: _, args: _,
} => op.default_args_type(), } => op.get_default_type(),
} }
} }
@ -174,7 +192,7 @@ fn num_expr_parser<'tokens, 'src: 'tokens>(
let num_atom = var let num_atom = var
.or(num_literal) .or(num_literal)
.map_with(|expr, e| (expr, e.span())) .map_with(|e, ctx| (e, ctx.span()))
// Atoms can also just be normal expressions, but surrounded with parentheses // Atoms can also just be normal expressions, but surrounded with parentheses
.or(num_expr.clone().delimited_by(just(Token::LParen), just(Token::RParen))) .or(num_expr.clone().delimited_by(just(Token::LParen), just(Token::RParen)))
// Attempt to recover anything that looks like a parenthesised expression but contains errors // Attempt to recover anything that looks like a parenthesised expression but contains errors
@ -297,39 +315,36 @@ pub(crate) fn parser<'tokens, 'src: 'tokens>(
[], [],
|span| (Expr::Error, span), |span| (Expr::Error, span),
))) )))
.or(expr)
.boxed(); .boxed();
let not_op = just(Token::Not) let unary_op = {
.map_with(|_, e| (UnaryOps::Not, e.span()))
.repeated()
.foldr(atom, |op, rhs| {
let span = op.1.start..rhs.1.end;
(Expr::unary_op(op.0, rhs, None), span.into())
})
.boxed();
let unary_temporal_op = {
let op = choice(( let op = choice((
just(Token::Not).to(UnaryOps::Not),
just(Token::Next).to(UnaryOps::Next), just(Token::Next).to(UnaryOps::Next),
just(Token::Eventually).to(UnaryOps::Eventually), just(Token::Eventually).to(UnaryOps::Eventually),
just(Token::Always).to(UnaryOps::Always), just(Token::Always).to(UnaryOps::Always),
)); ));
op.map_with(|op, e| (op, e.span())) op.map_with(|op, e| (op, e.span()))
.then(interval.clone().or_not()) .then(interval.clone().or_not())
.try_map(|(op, interval), _| match (op, interval) {
((UnaryOps::Not, _), Some((_, s))) => {
Err(Rich::custom(s, "Not (`!`) operator cannot have an interval"))
}
(o, i) => Ok((o, i)),
})
.repeated() .repeated()
.foldr(not_op, |(op, interval), rhs| { .foldr(atom, |(op, interval), rhs| {
let span = op.1.start..rhs.1.end; let span = op.1.start..rhs.1.end;
(Expr::unary_op(op.0, rhs, interval), span.into()) (Expr::unary_op(op.0, rhs, interval), span.into())
}) })
.boxed() .boxed()
}; };
let binary_temporal_op = unary_temporal_op let until_op = unary_op
.clone() .clone()
.then(just(Token::Until).to(BinaryOps::Until).then(interval.or_not())) .then(just(Token::Until).to(BinaryOps::Until).then(interval.or_not()))
.repeated() .repeated()
.foldr(unary_temporal_op, |(lhs, (op, interval)), rhs| { .foldr(unary_op, |(lhs, (op, interval)), rhs| {
let span = lhs.1.start..rhs.1.end; let span = lhs.1.start..rhs.1.end;
assert_eq!(op, BinaryOps::Until); assert_eq!(op, BinaryOps::Until);
(Expr::binary_op(op, (lhs, rhs), interval), span.into()) (Expr::binary_op(op, (lhs, rhs), interval), span.into())
@ -338,9 +353,9 @@ pub(crate) fn parser<'tokens, 'src: 'tokens>(
let and_op = { let and_op = {
let op = just(Token::And).to(BinaryOps::And); let op = just(Token::And).to(BinaryOps::And);
binary_temporal_op until_op
.clone() .clone()
.foldl(op.then(binary_temporal_op).repeated(), |a, (op, b)| { .foldl(op.then(until_op).repeated(), |a, (op, b)| {
let span = a.1.start..b.1.end; let span = a.1.start..b.1.end;
(Expr::binary_op(op, (a, b), None), span.into()) (Expr::binary_op(op, (a, b), None), span.into())
}) })