diff --git a/compiler/erg_compiler/codegen.rs b/compiler/erg_compiler/codegen.rs index 49754765..e296d981 100644 --- a/compiler/erg_compiler/codegen.rs +++ b/compiler/erg_compiler/codegen.rs @@ -1427,6 +1427,7 @@ impl PyCodeGenerator { TokenKind::Mod => Opcode310::BINARY_MODULO, TokenKind::AndOp => Opcode310::BINARY_AND, TokenKind::OrOp => Opcode310::BINARY_OR, + TokenKind::IsOp | TokenKind::IsNotOp => Opcode310::IS_OP, TokenKind::Less | TokenKind::LessEq | TokenKind::DblEq @@ -1456,6 +1457,8 @@ impl PyCodeGenerator { TokenKind::NotEq => 3, TokenKind::Gre => 4, TokenKind::GreEq => 5, + TokenKind::IsOp => 0, + TokenKind::IsNotOp => 1, TokenKind::LeftOpen | TokenKind::RightOpen | TokenKind::Closed @@ -1489,6 +1492,7 @@ impl PyCodeGenerator { | TokenKind::Mod | TokenKind::AndOp | TokenKind::OrOp => Opcode311::BINARY_OP, + TokenKind::IsOp | TokenKind::IsNotOp => Opcode311::IS_OP, TokenKind::Less | TokenKind::LessEq | TokenKind::DblEq @@ -1533,6 +1537,8 @@ impl PyCodeGenerator { TokenKind::NotEq => 3, TokenKind::Gre => 4, TokenKind::GreEq => 5, + TokenKind::IsOp => 0, + TokenKind::IsNotOp => 1, TokenKind::LeftOpen | TokenKind::RightOpen | TokenKind::Closed diff --git a/compiler/erg_compiler/context/initialize/mod.rs b/compiler/erg_compiler/context/initialize/mod.rs index d53c860a..5cc28cd4 100644 --- a/compiler/erg_compiler/context/initialize/mod.rs +++ b/compiler/erg_compiler/context/initialize/mod.rs @@ -2366,6 +2366,9 @@ impl Context { let M = mono_q("M", subtypeof(poly("Div", vec![ty_tp(M)]))); let op_t = bin_op(M.clone(), M.clone(), proj(M, "ModOutput")).quantify(); self.register_builtin_impl("__mod__", op_t, Const, Private); + let op_t = nd_proc(vec![kw("lhs", Obj), kw("rhs", Obj)], None, Bool); + self.register_builtin_impl("__is__!", op_t.clone(), Const, Private); + self.register_builtin_impl("__isnot__!", op_t, Const, Private); let E = mono_q("E", subtypeof(mono("Eq"))); let op_t = bin_op(E.clone(), E, Bool).quantify(); self.register_builtin_impl("__eq__", op_t.clone(), Const, Private); diff --git a/compiler/erg_compiler/effectcheck.rs b/compiler/erg_compiler/effectcheck.rs index 550f499f..232e9c3c 100644 --- a/compiler/erg_compiler/effectcheck.rs +++ b/compiler/erg_compiler/effectcheck.rs @@ -7,6 +7,7 @@ use erg_common::log; use erg_common::traits::{Locational, Stream}; use erg_common::vis::Visibility; use erg_common::Str; +use erg_parser::token::TokenKind; use Visibility::*; use crate::ty::HasType; @@ -419,6 +420,16 @@ impl SideEffectChecker { Expr::BinOp(bin) => { self.check_expr(&bin.lhs); self.check_expr(&bin.rhs); + if (bin.op.kind == TokenKind::IsOp || bin.op.kind == TokenKind::IsNotOp) + && !self.in_context_effects_allowed() + { + self.errs.push(EffectError::has_effect( + self.cfg.input.clone(), + line!() as usize, + expr, + self.full_path(), + )); + } } Expr::Lambda(lambda) => { let is_proc = lambda.is_procedural(); diff --git a/compiler/erg_compiler/error.rs b/compiler/erg_compiler/error.rs index d5adee5a..5875ef41 100644 --- a/compiler/erg_compiler/error.rs +++ b/compiler/erg_compiler/error.rs @@ -97,8 +97,8 @@ pub fn binop_to_dname(op: &str) -> &str { "contains" => "__contains__", "subof" => "__subof__", "supof" => "__supof__", - "is" => "__is__", - "isnot" => "__isnot__", + "is!" => "__is__!", + "isnot!" => "__isnot__!", "==" => "__eq__", "!=" => "__ne__", "<" => "__lt__", @@ -143,8 +143,8 @@ pub fn readable_name(name: &str) -> &str { "__contains__" => "`contains`", "__subof__" => "`subof`", "__supof__" => "`supof`", - "__is__" => "`is`", - "__isnot__" => "`isnot`", + "__is__!" => "`is!`", + "__isnot__!" => "`isnot!`", "__eq__" => "`==`", "__ne__" => "`!=`", "__lt__" => "`<`", diff --git a/compiler/erg_parser/lex.rs b/compiler/erg_parser/lex.rs index 45af3be8..26ac2b00 100644 --- a/compiler/erg_parser/lex.rs +++ b/compiler/erg_parser/lex.rs @@ -236,7 +236,7 @@ impl Lexer /*<'a>*/ { } // +, -, * etc. may be pre/bin - // and, or, is, isnot, in, notin, as, dot, cross may be bin/function + // and, or, is!, isnot!, in, notin, as, dot, cross may be bin/function const fn is_bin_position(&self) -> Option { match self.prev_token.category() { // unary: `[ +`, `= +`, `+ +`, `, +`, `:: +` @@ -648,8 +648,8 @@ impl Lexer /*<'a>*/ { "or" => OrOp, "in" => InOp, "notin" => NotInOp, - "is" => IsOp, - "isnot" => IsNotOp, + "is!" => IsOp, + "isnot!" => IsNotOp, "dot" => DotOp, "cross" => CrossOp, "ref" => RefOp, diff --git a/compiler/erg_parser/token.rs b/compiler/erg_parser/token.rs index 28c2a044..2fc64c6c 100644 --- a/compiler/erg_parser/token.rs +++ b/compiler/erg_parser/token.rs @@ -98,9 +98,9 @@ pub enum TokenKind { NotInOp, /// `sub` (subtype of) SubOp, - /// `is` + /// `is!` IsOp, - /// `isnot` + /// `isnot!` IsNotOp, /// `and` AndOp,