fix: compile-time eval bug

This commit is contained in:
Shunsuke Shibayama 2024-02-23 23:03:34 +09:00
parent ca88e82c9f
commit c9438f215a
5 changed files with 140 additions and 2 deletions

View file

@ -603,7 +603,7 @@ impl Context {
match acc {
Accessor::Ident(ident) => {
let obj = self.rec_get_const_obj(ident.inspect()).ok_or_else(|| {
EvalError::no_var_error(
EvalError::not_comptime_fn_error(
self.cfg.input.clone(),
line!() as usize,
ident.loc(),
@ -1170,6 +1170,20 @@ impl Context {
line!(),
))
}),
Pow => lhs.try_pow(rhs).ok_or_else(|| {
EvalErrors::from(EvalError::unreachable(
self.cfg.input.clone(),
fn_name!(),
line!(),
))
}),
Mod => lhs.try_mod(rhs).ok_or_else(|| {
EvalErrors::from(EvalError::unreachable(
self.cfg.input.clone(),
fn_name!(),
line!(),
))
}),
Gt => lhs.try_gt(rhs).ok_or_else(|| {
EvalErrors::from(EvalError::unreachable(
self.cfg.input.clone(),

View file

@ -215,6 +215,43 @@ impl LowerError {
)
}
pub fn not_comptime_fn_error(
input: Input,
errno: usize,
loc: Location,
caused_by: String,
name: &str,
similar_name: Option<&str>,
) -> Self {
let name = readable_name(name);
let hint = similar_name.map(|n| {
let n = n.with_color_and_attr(HINT, ATTR);
switch_lang!(
"japanese" => format!("似た名前の関数があります: {n}"),
"simplified_chinese" => format!("存在相同名称函数: {n}"),
"traditional_chinese" => format!("存在相同名稱函數: {n}"),
"english" => format!("exists a similar name function: {n}"),
)
});
let found = name.with_color_and_attr(ERR, ATTR);
Self::new(
ErrorCore::new(
vec![SubMessage::ambiguous_new(loc, vec![], hint)],
switch_lang!(
"japanese" => format!("{found}はコンパイル時関数ではありません"),
"simplified_chinese" => format!("{found}不是编译时函数"),
"traditional_chinese" => format!("{found}不是編譯時函數"),
"english" => format!("{found} is not a compile-time function"),
),
errno,
NameError,
loc,
),
input,
caused_by,
)
}
/// TODO: replace `no_var_error` with this function
pub fn detailed_no_var_error(
input: Input,

View file

@ -519,6 +519,7 @@ pub enum ValueObj {
Ellipsis,
NotImplemented,
NegInf,
/// different from `Float.Inf`
Inf,
#[default]
Illegal, // to avoid conversions with TryFrom
@ -977,7 +978,7 @@ impl ValueObj {
pub const fn is_num(&self) -> bool {
matches!(
self,
Self::Float(_) | Self::Int(_) | Self::Nat(_) | Self::Bool(_)
Self::Float(_) | Self::Int(_) | Self::Nat(_) | Self::Bool(_) | Self::Inf | Self::NegInf
)
}
@ -1373,6 +1374,36 @@ impl ValueObj {
}
}
pub fn try_pow(self, other: Self) -> Option<Self> {
match (self, other) {
(Self::Int(l), Self::Int(r)) => Some(Self::Int(l.pow(r.try_into().ok()?))),
(Self::Nat(l), Self::Nat(r)) => Some(Self::Nat(l.pow(r.try_into().ok()?))),
(Self::Float(l), Self::Float(r)) => Some(Self::Float(l.powf(r))),
(Self::Int(l), Self::Nat(r)) => Some(Self::Int(l.pow(r.try_into().ok()?))),
(Self::Nat(l), Self::Int(r)) => Some(Self::Nat(l.pow(r.try_into().ok()?))),
(Self::Float(l), Self::Nat(r)) => Some(Self::Float(l.powf(r as f64))),
(Self::Nat(l), Self::Float(r)) => Some(Self::Float((l as f64).powf(r))),
(Self::Float(l), Self::Int(r)) => Some(Self::Float(l.powi(r))),
(Self::Int(l), Self::Float(r)) => Some(Self::Float((l as f64).powf(r))),
_ => None,
}
}
pub fn try_mod(self, other: Self) -> Option<Self> {
match (self, other) {
(Self::Int(l), Self::Int(r)) => Some(Self::Int(l % r)),
(Self::Nat(l), Self::Nat(r)) => Some(Self::Nat(l % r)),
(Self::Float(l), Self::Float(r)) => Some(Self::Float(l % r)),
(Self::Int(l), Self::Nat(r)) => Some(Self::Int(l % r as i32)),
(Self::Nat(l), Self::Int(r)) => Some(Self::Int(l as i32 % r)),
(Self::Float(l), Self::Nat(r)) => Some(Self::Float(l % r as f64)),
(Self::Nat(l), Self::Float(r)) => Some(Self::Float(l as f64 % r)),
(Self::Float(l), Self::Int(r)) => Some(Self::Float(l % r as f64)),
(Self::Int(l), Self::Float(r)) => Some(Self::Float(l as f64 % r)),
_ => None,
}
}
pub fn try_gt(self, other: Self) -> Option<Self> {
match (self, other) {
(Self::Int(l), Self::Int(r)) => Some(Self::from(l > r)),
@ -1384,6 +1415,15 @@ impl ValueObj {
(Self::Nat(l), Self::Float(r)) => Some(Self::from(l as f64 > r)),
(Self::Float(l), Self::Int(r)) => Some(Self::from(l > r as f64)),
(Self::Int(l), Self::Float(r)) => Some(Self::from(l as f64 > r)),
(Self::Inf, Self::Inf) | (Self::NegInf, Self::NegInf) => Some(Self::Bool(false)),
(Self::Inf, Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_))
| (Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_), Self::NegInf) => {
Some(Self::Bool(true))
}
(Self::NegInf, Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_))
| (Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_), Self::Inf) => {
Some(Self::Bool(false))
}
_ => None,
}
}
@ -1399,6 +1439,15 @@ impl ValueObj {
(Self::Nat(l), Self::Float(r)) => Some(Self::from(l as f64 >= r)),
(Self::Float(l), Self::Int(r)) => Some(Self::from(l >= r as f64)),
(Self::Int(l), Self::Float(r)) => Some(Self::from(l as f64 >= r)),
(Self::Inf, Self::Inf) | (Self::NegInf, Self::NegInf) => Some(Self::Bool(true)),
(Self::Inf, Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_))
| (Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_), Self::NegInf) => {
Some(Self::Bool(true))
}
(Self::NegInf, Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_))
| (Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_), Self::Inf) => {
Some(Self::Bool(false))
}
_ => None,
}
}
@ -1414,6 +1463,15 @@ impl ValueObj {
(Self::Nat(l), Self::Float(r)) => Some(Self::from((l as f64) < r)),
(Self::Float(l), Self::Int(r)) => Some(Self::from(l < r as f64)),
(Self::Int(l), Self::Float(r)) => Some(Self::from((l as f64) < r)),
(Self::Inf, Self::Inf) | (Self::NegInf, Self::NegInf) => Some(Self::Bool(false)),
(Self::Inf, Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_))
| (Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_), Self::NegInf) => {
Some(Self::Bool(false))
}
(Self::NegInf, Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_))
| (Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_), Self::Inf) => {
Some(Self::Bool(true))
}
_ => None,
}
}
@ -1429,6 +1487,15 @@ impl ValueObj {
(Self::Nat(l), Self::Float(r)) => Some(Self::from((l as f64) <= r)),
(Self::Float(l), Self::Int(r)) => Some(Self::from(l <= r as f64)),
(Self::Int(l), Self::Float(r)) => Some(Self::from((l as f64) <= r)),
(Self::Inf, Self::Inf) | (Self::NegInf, Self::NegInf) => Some(Self::Bool(true)),
(Self::Inf, Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_))
| (Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_), Self::NegInf) => {
Some(Self::Bool(false))
}
(Self::NegInf, Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_))
| (Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_), Self::Inf) => {
Some(Self::Bool(true))
}
_ => None,
}
}
@ -1447,6 +1514,7 @@ impl ValueObj {
(Self::Str(l), Self::Str(r)) => Some(Self::from(l == r)),
(Self::Bool(l), Self::Bool(r)) => Some(Self::from(l == r)),
(Self::Type(l), Self::Type(r)) => Some(Self::from(l == r)),
(Self::Inf, Self::Inf) | (Self::NegInf, Self::NegInf) => Some(Self::Bool(true)),
// TODO:
_ => None,
}
@ -1466,6 +1534,7 @@ impl ValueObj {
(Self::Str(l), Self::Str(r)) => Some(Self::from(l != r)),
(Self::Bool(l), Self::Bool(r)) => Some(Self::from(l != r)),
(Self::Type(l), Self::Type(r)) => Some(Self::from(l != r)),
(Self::Inf, Self::Inf) | (Self::NegInf, Self::NegInf) => Some(Self::Bool(false)),
_ => None,
}
}