Merge pull request #203 from GreasySlug/fix/floordiv

[WIP] Implement floordiv operator
This commit is contained in:
Shunsuke Shibayama 2022-10-12 11:01:36 +09:00 committed by GitHub
commit fe1fd686d8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 107 additions and 13 deletions

View file

@ -33,6 +33,7 @@ pub enum Opcode {
BINARY_ADD = 23,
BINARY_SUBTRACT = 24,
BINARY_SUBSCR = 25,
BINARY_FLOOR_DIVIDE = 26,
BINARY_TRUE_DIVIDE = 27,
INPLACE_FLOOR_DIVIDE = 28,
INPLACE_TRUE_DIVIDE = 29,
@ -183,6 +184,7 @@ impl From<u8> for Opcode {
23 => BINARY_ADD,
24 => BINARY_SUBTRACT,
25 => BINARY_SUBSCR,
26 => BINARY_FLOOR_DIVIDE,
27 => BINARY_TRUE_DIVIDE,
28 => INPLACE_FLOOR_DIVIDE,
29 => INPLACE_TRUE_DIVIDE,

View file

@ -1163,6 +1163,7 @@ impl CodeGenerator {
TokenKind::Minus => BINARY_SUBTRACT,
TokenKind::Star => BINARY_MULTIPLY,
TokenKind::Slash => BINARY_TRUE_DIVIDE,
TokenKind::FloorDiv => BINARY_FLOOR_DIVIDE,
TokenKind::Pow => BINARY_POWER,
TokenKind::Mod => BINARY_MODULO,
TokenKind::AndOp => BINARY_AND,

View file

@ -52,6 +52,7 @@ fn try_get_op_kind_from_token(kind: TokenKind) -> EvalResult<OpKind> {
TokenKind::Minus => Ok(OpKind::Sub),
TokenKind::Star => Ok(OpKind::Mul),
TokenKind::Slash => Ok(OpKind::Div),
TokenKind::FloorDiv => Ok(OpKind::FloorDiv),
TokenKind::Pow => Ok(OpKind::Pow),
TokenKind::Mod => Ok(OpKind::Mod),
TokenKind::DblEq => Ok(OpKind::Eq),
@ -78,6 +79,7 @@ fn op_to_name(op: OpKind) -> &'static str {
OpKind::Sub => "__sub__",
OpKind::Mul => "__mul__",
OpKind::Div => "__div__",
OpKind::FloorDiv => "__floordiv__",
OpKind::Mod => "__mod__",
OpKind::Pow => "__pow__",
OpKind::Pos => "__pos__",
@ -664,6 +666,13 @@ impl Context {
line!(),
))
}),
FloorDiv => lhs.try_floordiv(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

@ -394,13 +394,25 @@ impl Context {
mul.register_builtin_decl("__mul__", op_t, Public);
mul.register_builtin_decl("Output", Type, Public);
/* Div */
let mut div = Self::builtin_poly_trait("Div", params, 2);
let mut div = Self::builtin_poly_trait("Div", params.clone(), 2);
div.register_superclass(builtin_poly("Output", vec![ty_tp(mono_q("R"))]), &output);
let op_t = fn1_met(mono_q("Self"), r, mono_proj(mono_q("Self"), "Output"));
let op_t = fn1_met(
mono_q("Self"),
r.clone(),
mono_proj(mono_q("Self"), "Output"),
);
let self_bound = subtypeof(mono_q("Self"), builtin_poly("Div", ty_params.clone()));
let op_t = quant(op_t, set! {r_bound, self_bound});
let op_t = quant(op_t, set! {r_bound.clone(), self_bound});
div.register_builtin_decl("__div__", op_t, Public);
div.register_builtin_decl("Output", Type, Public);
/* FloorDiv */
let mut floor_div = Self::builtin_poly_trait("FloorDiv", params, 2);
floor_div.register_superclass(builtin_poly("Output", vec![ty_tp(mono_q("R"))]), &output);
let op_t = fn1_met(mono_q("Self"), r, mono_proj(mono_q("Self"), "Output"));
let self_bound = subtypeof(mono_q("Self"), builtin_poly("FloorDiv", ty_params.clone()));
let op_t = quant(op_t, set! {r_bound, self_bound});
floor_div.register_builtin_decl("__floordiv__", op_t, Public);
floor_div.register_builtin_decl("Output", Type, Public);
self.register_builtin_type(builtin_mono("Unpack"), unpack, Const);
self.register_builtin_type(builtin_mono("InheritableType"), inheritable_type, Const);
self.register_builtin_type(builtin_mono("Named"), named, Const);
@ -433,7 +445,8 @@ impl Context {
self.register_builtin_type(builtin_poly("Add", ty_params.clone()), add, Const);
self.register_builtin_type(builtin_poly("Sub", ty_params.clone()), sub, Const);
self.register_builtin_type(builtin_poly("Mul", ty_params.clone()), mul, Const);
self.register_builtin_type(builtin_poly("Div", ty_params), div, Const);
self.register_builtin_type(builtin_poly("Div", ty_params.clone()), div, Const);
self.register_builtin_type(builtin_poly("FloorDiv", ty_params), floor_div, Const);
self.register_const_param_defaults(
"Eq",
vec![ConstTemplate::Obj(ValueObj::builtin_t(mono_q("Self")))],
@ -458,6 +471,10 @@ impl Context {
"Div",
vec![ConstTemplate::Obj(ValueObj::builtin_t(mono_q("Self")))],
);
self.register_const_param_defaults(
"FloorDiv",
vec![ConstTemplate::Obj(ValueObj::builtin_t(mono_q("Self")))],
);
}
fn init_builtin_classes(&mut self) {
@ -522,10 +539,18 @@ impl Context {
float_mul.register_builtin_const("PowOutput", ValueObj::builtin_t(Float));
float.register_trait(Float, builtin_poly("Mul", vec![ty_tp(Float)]), float_mul);
let mut float_div = Self::builtin_methods("Div", 2);
float_div.register_builtin_impl("__div__", op_t, Const, Public);
float_div.register_builtin_impl("__div__", op_t.clone(), Const, Public);
float_div.register_builtin_const("Output", ValueObj::builtin_t(Float));
float_div.register_builtin_const("ModOutput", ValueObj::builtin_t(Float));
float.register_trait(Float, builtin_poly("Div", vec![ty_tp(Float)]), float_div);
let mut float_floordiv = Self::builtin_methods("FloorDiv", 2);
float_floordiv.register_builtin_impl("__floordiv__", op_t, Const, Public);
float_floordiv.register_builtin_const("Output", ValueObj::builtin_t(Float));
float.register_trait(
Float,
builtin_poly("FloorDiv", vec![ty_tp(Float)]),
float_floordiv,
);
let mut float_mutizable = Self::builtin_methods("Mutizable", 2);
float_mutizable
.register_builtin_const("MutType!", ValueObj::builtin_t(builtin_mono("Float!")));
@ -573,10 +598,18 @@ impl Context {
ratio_mul.register_builtin_const("PowOutput", ValueObj::builtin_t(Ratio));
ratio.register_trait(Ratio, builtin_poly("Mul", vec![ty_tp(Ratio)]), ratio_mul);
let mut ratio_div = Self::builtin_methods("Div", 2);
ratio_div.register_builtin_impl("__div__", op_t, Const, Public);
ratio_div.register_builtin_impl("__div__", op_t.clone(), Const, Public);
ratio_div.register_builtin_const("Output", ValueObj::builtin_t(Ratio));
ratio_div.register_builtin_const("ModOutput", ValueObj::builtin_t(Ratio));
ratio.register_trait(Ratio, builtin_poly("Div", vec![ty_tp(Ratio)]), ratio_div);
let mut ratio_floordiv = Self::builtin_methods("FloorDiv", 2);
ratio_floordiv.register_builtin_impl("__floordiv__", op_t, Const, Public);
ratio_floordiv.register_builtin_const("Output", ValueObj::builtin_t(Ratio));
ratio.register_trait(
Ratio,
builtin_poly("FloorDiv", vec![ty_tp(Ratio)]),
ratio_floordiv,
);
let mut ratio_mutizable = Self::builtin_methods("Mutizable", 2);
ratio_mutizable
.register_builtin_const("MutType!", ValueObj::builtin_t(builtin_mono("Ratio!")));
@ -621,10 +654,18 @@ impl Context {
int_sub.register_builtin_const("Output", ValueObj::builtin_t(Int));
int.register_trait(Int, builtin_poly("Sub", vec![ty_tp(Int)]), int_sub);
let mut int_mul = Self::builtin_methods("Mul", 2);
int_mul.register_builtin_impl("__mul__", op_t, Const, Public);
int_mul.register_builtin_impl("__mul__", op_t.clone(), Const, Public);
int_mul.register_builtin_const("Output", ValueObj::builtin_t(Int));
int_mul.register_builtin_const("PowOutput", ValueObj::builtin_t(Nat));
int.register_trait(Int, builtin_poly("Mul", vec![ty_tp(Int)]), int_mul);
let mut int_floordiv = Self::builtin_methods("FloorDiv", 2);
int_floordiv.register_builtin_impl("__floordiv__", op_t, Const, Public);
int_floordiv.register_builtin_const("Output", ValueObj::builtin_t(Int));
int.register_trait(
Int,
builtin_poly("FloorDiv", vec![ty_tp(Int)]),
int_floordiv,
);
let mut int_mutizable = Self::builtin_methods("Mutizable", 2);
int_mutizable.register_builtin_const("MutType!", ValueObj::builtin_t(builtin_mono("Int!")));
int.register_trait(Int, builtin_mono("Mutizable"), int_mutizable);
@ -676,9 +717,17 @@ impl Context {
nat_add.register_builtin_const("Output", ValueObj::builtin_t(Nat));
nat.register_trait(Nat, builtin_poly("Add", vec![ty_tp(Nat)]), nat_add);
let mut nat_mul = Self::builtin_methods("Mul", 2);
nat_mul.register_builtin_impl("__mul__", op_t, Const, Public);
nat_mul.register_builtin_impl("__mul__", op_t.clone(), Const, Public);
nat_mul.register_builtin_const("Output", ValueObj::builtin_t(Nat));
nat.register_trait(Nat, builtin_poly("Mul", vec![ty_tp(Nat)]), nat_mul);
let mut nat_floordiv = Self::builtin_methods("FloorDiv", 2);
nat_floordiv.register_builtin_impl("__floordiv__", op_t, Const, Public);
nat_floordiv.register_builtin_const("Output", ValueObj::builtin_t(Nat));
nat.register_trait(
Nat,
builtin_poly("FloorDiv", vec![ty_tp(Nat)]),
nat_floordiv,
);
let mut nat_mutizable = Self::builtin_methods("Mutizable", 2);
nat_mutizable.register_builtin_const("MutType!", ValueObj::builtin_t(builtin_mono("Nat!")));
nat.register_trait(Nat, builtin_mono("Mutizable"), nat_mutizable);
@ -710,10 +759,6 @@ impl Context {
let mut bool_eq = Self::builtin_methods("Eq", 2);
bool_eq.register_builtin_impl("__eq__", fn1_met(Bool, Bool, Bool), Const, Public);
bool_.register_trait(Bool, builtin_poly("Eq", vec![ty_tp(Bool)]), bool_eq);
let mut bool_add = Self::builtin_methods("Add", 2);
bool_add.register_builtin_impl("__add__", fn1_met(Bool, Bool, Int), Const, Public);
bool_add.register_builtin_const("Output", ValueObj::builtin_t(Nat));
bool_.register_trait(Bool, builtin_poly("Add", vec![ty_tp(Bool)]), bool_add);
let mut bool_mutizable = Self::builtin_methods("Mutizable", 2);
bool_mutizable
.register_builtin_const("MutType!", ValueObj::builtin_t(builtin_mono("Bool!")));
@ -1860,6 +1905,15 @@ impl Context {
},
);
self.register_builtin_impl("__div__", op_t, Const, Private);
let op_t = bin_op(l.clone(), r.clone(), mono_proj(mono_q("L"), "Output"));
let op_t = quant(
op_t,
set! {
static_instance("R", Type),
subtypeof(l.clone(), builtin_poly("FloorDiv", params.clone()))
},
);
self.register_builtin_impl("__floordiv__", op_t, Const, Private);
let m = mono_q("M");
let op_t = bin_op(m.clone(), m.clone(), mono_proj(m.clone(), "PowOutput"));
let op_t = quant(op_t, set! {subtypeof(m, builtin_poly("Mul", vec![]))});

View file

@ -1381,7 +1381,7 @@ impl Context {
.super_classes
.iter()
.chain(ctx.super_traits.iter())
.map(|sup| self.get_nominal_type_ctx(sup).unwrap());
.map(|sup| self.get_nominal_type_ctx(sup).expect("compiler bug: sup not found"));
Some(vec![ctx].into_iter().chain(sups))
}

View file

@ -25,6 +25,7 @@ pub fn binop_to_dname(op: &str) -> &str {
"-" => "__sub__",
"*" => "__mul__",
"/" => "__div__",
"//" => "__floordiv__",
"**" => "__pow__",
"%" => "__mod__",
".." => "__rng__",
@ -66,6 +67,7 @@ pub fn readable_name(name: &str) -> &str {
"__sub__" => "`-`",
"__mul__" => "`*`",
"__div__" => "`/`",
"__floordiv__" => "`//`",
"__pow__" => "`**`",
"__mod__" => "`%`",
"__rng__" => "`..`",

View file

@ -17,6 +17,7 @@ pub enum OpKind {
Sub,
Mul,
Div,
FloorDiv,
Pow,
Mod,
Pos,
@ -45,6 +46,7 @@ impl fmt::Display for OpKind {
Self::Sub => write!(f, "-"),
Self::Mul => write!(f, "*"),
Self::Div => write!(f, "/"),
Self::FloorDiv => write!(f, "//"),
Self::Pow => write!(f, "**"),
Self::Mod => write!(f, "%"),
Self::Pos => write!(f, "+"),

View file

@ -686,6 +686,30 @@ impl ValueObj {
}
}
pub fn try_floordiv(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).floor())),
(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).floor())),
(Self::Nat(l), Self::Float(r)) => Some(Self::Float((l as f64 / r).floor())),
(Self::Float(l), Self::Int(r)) => Some(Self::Float((l / r as f64).floor())),
(Self::Int(l), Self::Float(r)) => Some(Self::Float((l as f64 / r).floor())),
(Self::Mut(m), other) => {
{
let ref_m = &mut *m.borrow_mut();
*ref_m = mem::take(ref_m).try_div(other)?;
}
Some(Self::Mut(m))
}
(self_, Self::Mut(m)) => self_.try_floordiv(m.borrow().clone()),
// TODO: x//±Inf = 0
_ => None,
}
}
pub fn try_gt(self, other: Self) -> Option<Self> {
match (self, other) {
(Self::Int(l), Self::Int(r)) => Some(Self::from(l > r)),