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