diff --git a/compiler/erg_common/opcode.rs b/compiler/erg_common/opcode.rs index c0f0c20b..63e71baa 100644 --- a/compiler/erg_common/opcode.rs +++ b/compiler/erg_common/opcode.rs @@ -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 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, diff --git a/compiler/erg_compiler/codegen.rs b/compiler/erg_compiler/codegen.rs index 39d68594..fd9baac6 100644 --- a/compiler/erg_compiler/codegen.rs +++ b/compiler/erg_compiler/codegen.rs @@ -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, diff --git a/compiler/erg_compiler/context/eval.rs b/compiler/erg_compiler/context/eval.rs index 76680742..bf1643c8 100644 --- a/compiler/erg_compiler/context/eval.rs +++ b/compiler/erg_compiler/context/eval.rs @@ -52,6 +52,7 @@ fn try_get_op_kind_from_token(kind: TokenKind) -> EvalResult { 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(), diff --git a/compiler/erg_compiler/context/initialize/mod.rs b/compiler/erg_compiler/context/initialize/mod.rs index ebfd0a88..af4664a8 100644 --- a/compiler/erg_compiler/context/initialize/mod.rs +++ b/compiler/erg_compiler/context/initialize/mod.rs @@ -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![]))}); diff --git a/compiler/erg_compiler/context/inquire.rs b/compiler/erg_compiler/context/inquire.rs index 46f9bd7e..b774d32a 100644 --- a/compiler/erg_compiler/context/inquire.rs +++ b/compiler/erg_compiler/context/inquire.rs @@ -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)) } diff --git a/compiler/erg_compiler/error.rs b/compiler/erg_compiler/error.rs index efbb743d..2383c380 100644 --- a/compiler/erg_compiler/error.rs +++ b/compiler/erg_compiler/error.rs @@ -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__" => "`..`", diff --git a/compiler/erg_type/typaram.rs b/compiler/erg_type/typaram.rs index c3bb7470..a40eb7d2 100644 --- a/compiler/erg_type/typaram.rs +++ b/compiler/erg_type/typaram.rs @@ -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, "+"), diff --git a/compiler/erg_type/value.rs b/compiler/erg_type/value.rs index 4328d4ef..2d36ea49 100644 --- a/compiler/erg_type/value.rs +++ b/compiler/erg_type/value.rs @@ -686,6 +686,30 @@ impl ValueObj { } } + pub fn try_floordiv(self, other: Self) -> Option { + 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 { match (self, other) { (Self::Int(l), Self::Int(r)) => Some(Self::from(l > r)),