fix(argus): parse errors
This commit is contained in:
parent
9d0f7ef2ee
commit
019797f344
6 changed files with 64 additions and 67 deletions
|
|
@ -14,6 +14,7 @@ ariadne = { version = "0.3.0", optional = true }
|
|||
chumsky = { version = "1.0.0-alpha.6", features = ["default", "label"] }
|
||||
derive_more = "0.99.17"
|
||||
enum_dispatch = "0.3.12"
|
||||
hashbrown = "0.14.1"
|
||||
itertools = "0.11"
|
||||
num-traits = "0.2.16"
|
||||
paste = "1.0.14"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Expression tree for Argus specifications
|
||||
|
||||
use std::collections::HashSet;
|
||||
use hashbrown::HashMap;
|
||||
|
||||
mod bool_expr;
|
||||
pub mod iter;
|
||||
|
|
@ -13,7 +13,7 @@ pub use num_expr::*;
|
|||
pub use traits::*;
|
||||
|
||||
use self::iter::AstIter;
|
||||
use crate::{ArgusResult, Error};
|
||||
use crate::{ArgusResult, Error, Type};
|
||||
|
||||
/// A trait representing expressions
|
||||
#[enum_dispatch]
|
||||
|
|
@ -155,7 +155,7 @@ pub enum Expr {
|
|||
/// definitions for variables.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct ExprBuilder {
|
||||
declarations: HashSet<String>,
|
||||
pub(crate) declarations: HashMap<String, Type>,
|
||||
}
|
||||
|
||||
impl ExprBuilder {
|
||||
|
|
@ -188,37 +188,33 @@ impl ExprBuilder {
|
|||
|
||||
/// Declare a boolean variable
|
||||
pub fn bool_var(&mut self, name: String) -> ArgusResult<BoolExpr> {
|
||||
if self.declarations.insert(name.clone()) {
|
||||
Ok((BoolVar { name }).into())
|
||||
} else {
|
||||
Err(Error::IdentifierRedeclaration)
|
||||
match self.declarations.insert(name.clone(), Type::Bool) {
|
||||
None | Some(Type::Bool) => Ok((BoolVar { name }).into()),
|
||||
_ => Err(Error::IdentifierRedeclaration),
|
||||
}
|
||||
}
|
||||
|
||||
/// Declare a integer variable
|
||||
pub fn int_var(&mut self, name: String) -> ArgusResult<NumExpr> {
|
||||
if self.declarations.insert(name.clone()) {
|
||||
Ok((IntVar { name }).into())
|
||||
} else {
|
||||
Err(Error::IdentifierRedeclaration)
|
||||
match self.declarations.insert(name.clone(), Type::Int) {
|
||||
None | Some(Type::Int) => Ok((IntVar { name }).into()),
|
||||
_ => Err(Error::IdentifierRedeclaration),
|
||||
}
|
||||
}
|
||||
|
||||
/// Declare a unsigned integer variable
|
||||
pub fn uint_var(&mut self, name: String) -> ArgusResult<NumExpr> {
|
||||
if self.declarations.insert(name.clone()) {
|
||||
Ok((UIntVar { name }).into())
|
||||
} else {
|
||||
Err(Error::IdentifierRedeclaration)
|
||||
match self.declarations.insert(name.clone(), Type::UInt) {
|
||||
None | Some(Type::UInt) => Ok((UIntVar { name }).into()),
|
||||
_ => Err(Error::IdentifierRedeclaration),
|
||||
}
|
||||
}
|
||||
|
||||
/// Declare a floating point variable
|
||||
pub fn float_var(&mut self, name: String) -> ArgusResult<NumExpr> {
|
||||
if self.declarations.insert(name.clone()) {
|
||||
Ok((FloatVar { name }).into())
|
||||
} else {
|
||||
Err(Error::IdentifierRedeclaration)
|
||||
match self.declarations.insert(name.clone(), Type::Float) {
|
||||
None | Some(Type::Float) => Ok((FloatVar { name }).into()),
|
||||
_ => Err(Error::IdentifierRedeclaration),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,8 +16,39 @@ pub use crate::core::{expr, signals};
|
|||
pub use crate::parser::parse_str;
|
||||
pub use crate::semantics::{BooleanSemantics, QuantitativeSemantics, Trace};
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
|
||||
pub(crate) enum Type {
|
||||
#[default]
|
||||
Unknown,
|
||||
Bool,
|
||||
UInt,
|
||||
Int,
|
||||
Float,
|
||||
}
|
||||
|
||||
impl Type {
|
||||
/// Get the lowest common supertype for the given types to a common
|
||||
fn get_common_cast(self, other: Self) -> Self {
|
||||
use Type::*;
|
||||
match (self, other) {
|
||||
(Unknown, other) | (other, Unknown) => other,
|
||||
(Bool, ty) | (ty, Bool) => ty,
|
||||
(UInt, Int) => Float,
|
||||
(UInt, Float) => Float,
|
||||
(Int, UInt) => Float,
|
||||
(Int, Float) => Float,
|
||||
(Float, UInt) => Float,
|
||||
(Float, Int) => Float,
|
||||
(lhs, rhs) => {
|
||||
assert_eq!(lhs, rhs);
|
||||
rhs
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Errors generated by all Argus components.
|
||||
#[derive(Error, Debug)]
|
||||
#[derive(Error, Debug, PartialEq, Eq)]
|
||||
pub enum Error {
|
||||
/// An identifier has been redeclared in a specification.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -87,13 +87,13 @@ pub fn lexer<'src>() -> impl Parser<'src, &'src str, Output<'src>, Error<'src>>
|
|||
// A parser for numbers
|
||||
let digits = text::digits(10).to_slice();
|
||||
|
||||
let frac = just('.').then(digits);
|
||||
let frac = just('.').then(digits.or_not());
|
||||
|
||||
let exp = just('e').or(just('E')).then(one_of("+-").or_not()).then(digits);
|
||||
|
||||
let floating_number = just('-')
|
||||
.or_not()
|
||||
.then(digits)
|
||||
.then(digits.or_not())
|
||||
.then(choice((frac.then(exp).to_slice(), frac.to_slice(), exp.to_slice())))
|
||||
// .then(frac.or_not())
|
||||
// .then(exp.or_not())
|
||||
|
|
@ -104,13 +104,9 @@ pub fn lexer<'src>() -> impl Parser<'src, &'src str, Output<'src>, Error<'src>>
|
|||
let signed_int = one_of("+-")
|
||||
// .or_not()
|
||||
.then(digits)
|
||||
.then(frac.not().or(exp.not()))
|
||||
.to_slice()
|
||||
.map(|s: &str| Token::Int(s.parse().unwrap()));
|
||||
let unsigned_int = digits
|
||||
.then(frac.not().or(exp.not()))
|
||||
.to_slice()
|
||||
.map(|s: &str| Token::UInt(s.parse().unwrap()));
|
||||
let unsigned_int = digits.to_slice().map(|s: &str| Token::UInt(s.parse().unwrap()));
|
||||
|
||||
let number = choice((floating_number, signed_int, unsigned_int));
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ use chumsky::prelude::Rich;
|
|||
use lexer::{lexer, Token};
|
||||
use syntax::{parser, Expr, Interval};
|
||||
|
||||
use crate::Type;
|
||||
|
||||
/// Parse a string expression into a concrete Argus expression.
|
||||
pub fn parse_str(src: &str) -> Result<crate::core::expr::Expr, Vec<Rich<'_, String>>> {
|
||||
use chumsky::prelude::{Input, Parser};
|
||||
|
|
@ -79,26 +81,26 @@ fn ast_to_expr<'tokens, 'src: 'tokens>(
|
|||
ctx: &mut ExprBuilder,
|
||||
) -> Result<crate::core::expr::Expr, Rich<'tokens, Token<'src>, lexer::Span>> {
|
||||
match ast {
|
||||
Expr::Error => unreachable!("Errors should have been caught by parser"),
|
||||
Expr::Error => Err(Rich::custom(span, "Errors should have been caught by parser")),
|
||||
Expr::Bool(value) => Ok(ctx.bool_const(*value).into()),
|
||||
Expr::Int(value) => Ok(ctx.int_const(*value).into()),
|
||||
Expr::UInt(value) => Ok(ctx.uint_const(*value).into()),
|
||||
Expr::Float(value) => Ok(ctx.float_const(*value).into()),
|
||||
Expr::Var { name, kind } => match kind {
|
||||
syntax::Type::Unknown => Err(Rich::custom(span, "All variables must have defined type by now.")),
|
||||
syntax::Type::Bool => ctx
|
||||
Type::Unknown => Err(Rich::custom(span, "All variables must have defined type by now.")),
|
||||
Type::Bool => ctx
|
||||
.bool_var(name.to_string())
|
||||
.map(|var| var.into())
|
||||
.map_err(|err| Rich::custom(span, err.to_string())),
|
||||
syntax::Type::UInt => ctx
|
||||
Type::UInt => ctx
|
||||
.uint_var(name.to_string())
|
||||
.map(|var| var.into())
|
||||
.map_err(|err| Rich::custom(span, err.to_string())),
|
||||
syntax::Type::Int => ctx
|
||||
Type::Int => ctx
|
||||
.int_var(name.to_string())
|
||||
.map(|var| var.into())
|
||||
.map_err(|err| Rich::custom(span, err.to_string())),
|
||||
syntax::Type::Float => ctx
|
||||
Type::Float => ctx
|
||||
.float_var(name.to_string())
|
||||
.map(|var| var.into())
|
||||
.map_err(|err| Rich::custom(span, err.to_string())),
|
||||
|
|
|
|||
|
|
@ -3,40 +3,10 @@ use chumsky::prelude::*;
|
|||
use chumsky::Parser;
|
||||
|
||||
use super::lexer::{Span, Token};
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
|
||||
pub enum Type {
|
||||
#[default]
|
||||
Unknown,
|
||||
Bool,
|
||||
UInt,
|
||||
Int,
|
||||
Float,
|
||||
}
|
||||
|
||||
impl Type {
|
||||
/// Get the lowest common supertype for the given types to a common
|
||||
fn get_common_cast(self, other: Self) -> Self {
|
||||
use Type::*;
|
||||
match (self, other) {
|
||||
(Unknown, other) | (other, Unknown) => other,
|
||||
(Bool, ty) | (ty, Bool) => ty,
|
||||
(UInt, Int) => Float,
|
||||
(UInt, Float) => Float,
|
||||
(Int, UInt) => Float,
|
||||
(Int, Float) => Float,
|
||||
(Float, UInt) => Float,
|
||||
(Float, Int) => Float,
|
||||
(lhs, rhs) => {
|
||||
assert_eq!(lhs, rhs);
|
||||
rhs
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
use crate::Type;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Interval<'src> {
|
||||
pub(crate) struct Interval<'src> {
|
||||
pub a: Option<Box<Spanned<Expr<'src>>>>,
|
||||
pub b: Option<Box<Spanned<Expr<'src>>>>,
|
||||
}
|
||||
|
|
@ -98,7 +68,7 @@ impl BinaryOps {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Expr<'src> {
|
||||
pub(crate) enum Expr<'src> {
|
||||
Error,
|
||||
Bool(bool),
|
||||
Int(i64),
|
||||
|
|
@ -258,7 +228,7 @@ fn num_expr_parser<'tokens, 'src: 'tokens>(
|
|||
})
|
||||
}
|
||||
|
||||
pub fn parser<'tokens, 'src: 'tokens>(
|
||||
pub(crate) fn parser<'tokens, 'src: 'tokens>(
|
||||
) -> impl Parser<'tokens, ParserInput<'tokens, 'src>, Spanned<Expr<'src>>, Error<'tokens, 'src>> + Clone {
|
||||
let interval = {
|
||||
let num_literal = select! {
|
||||
|
|
@ -327,6 +297,7 @@ pub fn parser<'tokens, 'src: 'tokens>(
|
|||
[],
|
||||
|span| (Expr::Error, span),
|
||||
)))
|
||||
.or(expr)
|
||||
.boxed();
|
||||
|
||||
let not_op = just(Token::Not)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue