Skip to content

Commit 027a25c

Browse files
authored
Merge branch 'master' into string.__repr__
2 parents 70fb3f6 + 28142e0 commit 027a25c

22 files changed

+336
-144
lines changed

compiler/src/error.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use rustpython_parser::error::{ParseError, ParseErrorType};
1+
use rustpython_parser::error::{LexicalErrorType, ParseError, ParseErrorType};
22
use rustpython_parser::location::Location;
33

44
use std::error::Error;
@@ -40,6 +40,19 @@ pub enum CompileErrorType {
4040
InvalidYield,
4141
}
4242

43+
impl CompileError {
44+
pub fn is_tab_error(&self) -> bool {
45+
if let CompileErrorType::Parse(parse) = &self.error {
46+
if let ParseErrorType::Lexical(lex) = parse {
47+
if let LexicalErrorType::TabError = lex {
48+
return true;
49+
}
50+
}
51+
}
52+
false
53+
}
54+
}
55+
4356
impl fmt::Display for CompileError {
4457
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4558
match &self.error {

parser/src/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub enum LexicalErrorType {
2020
StringError,
2121
UnicodeError,
2222
NestingError,
23+
TabError,
2324
DefaultArgumentError,
2425
PositionalArgumentError,
2526
DuplicateKeywordArgumentError,
@@ -35,6 +36,9 @@ impl fmt::Display for LexicalErrorType {
3536
LexicalErrorType::FStringError(error) => write!(f, "Got error in f-string: {}", error),
3637
LexicalErrorType::UnicodeError => write!(f, "Got unexpected unicode"),
3738
LexicalErrorType::NestingError => write!(f, "Got unexpected nesting"),
39+
LexicalErrorType::TabError => {
40+
write!(f, "inconsistent use of tabs and spaces in indentation")
41+
}
3842
LexicalErrorType::DefaultArgumentError => {
3943
write!(f, "non-default argument follows default argument")
4044
}

parser/src/lexer.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,7 @@ impl IndentationLevel {
3838
} else {
3939
Err(LexicalError {
4040
location,
41-
error: LexicalErrorType::OtherError(
42-
"inconsistent use of tabs and spaces in indentation".to_string(),
43-
),
41+
error: LexicalErrorType::TabError,
4442
})
4543
}
4644
} else if self.tabs > other.tabs {
@@ -49,9 +47,7 @@ impl IndentationLevel {
4947
} else {
5048
Err(LexicalError {
5149
location,
52-
error: LexicalErrorType::OtherError(
53-
"inconsistent use of tabs and spaces in indentation".to_string(),
54-
),
50+
error: LexicalErrorType::TabError,
5551
})
5652
}
5753
} else {

tests/snippets/dict.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,3 +251,6 @@ def __eq__(self, other):
251251
assert isinstance(c, set)
252252
assert c == {'bla', 'c', 'd', 'f'}
253253

254+
assert not {}.__ne__({})
255+
assert {}.__ne__({'a':'b'})
256+
assert {}.__ne__(1) == NotImplemented

tests/snippets/invalid_syntax.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,14 @@ def valid_func():
1414
else:
1515
raise AssertionError("Must throw syntax error")
1616

17+
src = """
18+
if True:
19+
pass
20+
\tpass
21+
"""
22+
23+
with assert_raises(TabError):
24+
compile(src, '', 'exec')
25+
1726
with assert_raises(SyntaxError):
1827
compile('0xX', 'test.py', 'exec')

tests/snippets/list.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,3 +488,47 @@ def bad_iter_assign():
488488
assert x == [0, 1, 2, 3, 4, 5]
489489
x = list(range(10))
490490
del x[-5:-1:-1]
491+
492+
assert [1, 2].__ne__([])
493+
assert [2, 1].__ne__([1, 2])
494+
assert not [1, 2].__ne__([1, 2])
495+
assert [1, 2].__ne__(1) == NotImplemented
496+
497+
# list gt, ge, lt, le
498+
assert_raises(TypeError, lambda: [0, []] < [0, 0])
499+
assert_raises(TypeError, lambda: [0, []] <= [0, 0])
500+
assert_raises(TypeError, lambda: [0, []] > [0, 0])
501+
assert_raises(TypeError, lambda: [0, []] >= [0, 0])
502+
503+
assert_raises(TypeError, lambda: [0, 0] < [0, []])
504+
assert_raises(TypeError, lambda: [0, 0] <= [0, []])
505+
assert_raises(TypeError, lambda: [0, 0] > [0, []])
506+
assert_raises(TypeError, lambda: [0, 0] >= [0, []])
507+
508+
assert [0, 0] < [1, -1]
509+
assert [0, 0] < [0, 0, 1]
510+
assert [0, 0] < [0, 0, -1]
511+
assert [0, 0] <= [0, 0, -1]
512+
assert not [0, 0, 0, 0] <= [0, -1]
513+
514+
assert [0, 0] > [-1, 1]
515+
assert [0, 0] >= [-1, 1]
516+
assert [0, 0, 0] >= [-1, 1]
517+
518+
assert [0, 0] <= [0, 1]
519+
assert [0, 0] <= [0, 0]
520+
assert [0, 0] <= [0, 0]
521+
assert not [0, 0] > [0, 0]
522+
assert not [0, 0] < [0, 0]
523+
524+
assert not [float('nan'), float('nan')] <= [float('nan'), 1]
525+
assert not [float('nan'), float('nan')] <= [float('nan'), float('nan')]
526+
assert not [float('nan'), float('nan')] >= [float('nan'), float('nan')]
527+
assert not [float('nan'), float('nan')] < [float('nan'), float('nan')]
528+
assert not [float('nan'), float('nan')] > [float('nan'), float('nan')]
529+
530+
assert [float('inf'), float('inf')] >= [float('inf'), 1]
531+
assert [float('inf'), float('inf')] <= [float('inf'), float('inf')]
532+
assert [float('inf'), float('inf')] >= [float('inf'), float('inf')]
533+
assert not [float('inf'), float('inf')] < [float('inf'), float('inf')]
534+
assert not [float('inf'), float('inf')] > [float('inf'), float('inf')]

tests/snippets/set.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,3 +327,13 @@ def __hash__(self):
327327
assert x == (EqObject(x) == EqObject(x))
328328
s = {EqObject(x)}
329329
assert EqObject(x) in s
330+
331+
assert set([1, 2]).__ne__(set())
332+
assert not set([1, 2]).__ne__(set([2, 1]))
333+
assert set().__ne__(1) == NotImplemented
334+
335+
assert frozenset([1, 2]).__ne__(set())
336+
assert frozenset([1, 2]).__ne__(frozenset())
337+
assert not frozenset([1, 2]).__ne__(set([2, 1]))
338+
assert not frozenset([1, 2]).__ne__(frozenset([2, 1]))
339+
assert frozenset().__ne__(1) == NotImplemented

tests/snippets/strings.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from testutils import assert_raises
22

3+
assert "".__eq__(1) == NotImplemented
34
assert "a" == 'a'
45
assert """a""" == "a"
56
assert len(""" " "" " "" """) == 11
@@ -318,3 +319,8 @@ def try_mutate_str():
318319
assert chr(9999).__repr__() == "'✏'"
319320
assert chr(99999).__repr__() == "'𘚟'"
320321
assert chr(999999).__repr__() == "'\\U000f423f'"
322+
323+
assert "a".__ne__("b")
324+
assert not "a".__ne__("a")
325+
assert not "".__ne__("")
326+
assert "".__ne__(1) == NotImplemented

tests/snippets/tuple.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from testutils import assert_raises
2+
13
assert (1,2) == (1,2)
24

35
x = (1,2)
@@ -47,3 +49,45 @@ def __eq__(self, x):
4749
a = ()
4850
b = ()
4951
assert a is b
52+
53+
assert (1,).__ne__((2,))
54+
assert not (1,).__ne__((1,))
55+
56+
# tuple gt, ge, lt, le
57+
assert_raises(TypeError, lambda: (0, ()) < (0, 0))
58+
assert_raises(TypeError, lambda: (0, ()) <= (0, 0))
59+
assert_raises(TypeError, lambda: (0, ()) > (0, 0))
60+
assert_raises(TypeError, lambda: (0, ()) >= (0, 0))
61+
62+
assert_raises(TypeError, lambda: (0, 0) < (0, ()))
63+
assert_raises(TypeError, lambda: (0, 0) <= (0, ()))
64+
assert_raises(TypeError, lambda: (0, 0) > (0, ()))
65+
assert_raises(TypeError, lambda: (0, 0) >= (0, ()))
66+
67+
assert (0, 0) < (1, -1)
68+
assert (0, 0) < (0, 0, 1)
69+
assert (0, 0) < (0, 0, -1)
70+
assert (0, 0) <= (0, 0, -1)
71+
assert not (0, 0, 0, 0) <= (0, -1)
72+
73+
assert (0, 0) > (-1, 1)
74+
assert (0, 0) >= (-1, 1)
75+
assert (0, 0, 0) >= (-1, 1)
76+
77+
assert (0, 0) <= (0, 1)
78+
assert (0, 0) <= (0, 0)
79+
assert (0, 0) <= (0, 0)
80+
assert not (0, 0) > (0, 0)
81+
assert not (0, 0) < (0, 0)
82+
83+
assert not (float('nan'), float('nan')) <= (float('nan'), 1)
84+
assert not (float('nan'), float('nan')) <= (float('nan'), float('nan'))
85+
assert not (float('nan'), float('nan')) >= (float('nan'), float('nan'))
86+
assert not (float('nan'), float('nan')) < (float('nan'), float('nan'))
87+
assert not (float('nan'), float('nan')) > (float('nan'), float('nan'))
88+
89+
assert (float('inf'), float('inf')) >= (float('inf'), 1)
90+
assert (float('inf'), float('inf')) <= (float('inf'), float('inf'))
91+
assert (float('inf'), float('inf')) >= (float('inf'), float('inf'))
92+
assert not (float('inf'), float('inf')) < (float('inf'), float('inf'))
93+
assert not (float('inf'), float('inf')) > (float('inf'), float('inf'))

vm/src/builtins.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -850,6 +850,8 @@ pub fn make_module(vm: &VirtualMachine, module: PyObjectRef) {
850850
"RuntimeError" => ctx.exceptions.runtime_error.clone(),
851851
"ReferenceError" => ctx.exceptions.reference_error.clone(),
852852
"SyntaxError" => ctx.exceptions.syntax_error.clone(),
853+
"IndentationError" => ctx.exceptions.indentation_error.clone(),
854+
"TabError" => ctx.exceptions.tab_error.clone(),
853855
"NotImplementedError" => ctx.exceptions.not_implemented_error.clone(),
854856
"TypeError" => ctx.exceptions.type_error.clone(),
855857
"ValueError" => ctx.exceptions.value_error.clone(),

vm/src/exceptions.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,8 @@ pub struct ExceptionZoo {
229229
pub runtime_error: PyClassRef,
230230
pub stop_iteration: PyClassRef,
231231
pub syntax_error: PyClassRef,
232+
pub indentation_error: PyClassRef,
233+
pub tab_error: PyClassRef,
232234
pub system_error: PyClassRef,
233235
pub type_error: PyClassRef,
234236
pub value_error: PyClassRef,
@@ -284,6 +286,8 @@ impl ExceptionZoo {
284286
let permission_error = create_type("PermissionError", &type_type, &os_error);
285287
let file_exists_error = create_type("FileExistsError", &type_type, &os_error);
286288
let eof_error = create_type("EOFError", &type_type, &exception_type);
289+
let indentation_error = create_type("IndentationError", &type_type, &syntax_error);
290+
let tab_error = create_type("TabError", &type_type, &indentation_error);
287291
let unicode_error = create_type("UnicodeError", &type_type, &value_error);
288292
let unicode_decode_error = create_type("UnicodeDecodeError", &type_type, &unicode_error);
289293
let unicode_encode_error = create_type("UnicodeEncodeError", &type_type, &unicode_error);
@@ -327,6 +331,8 @@ impl ExceptionZoo {
327331
runtime_error,
328332
stop_iteration,
329333
syntax_error,
334+
indentation_error,
335+
tab_error,
330336
system_error,
331337
type_error,
332338
value_error,

vm/src/obj/objdict.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,15 @@ impl PyDictRef {
146146
}
147147
}
148148

149+
fn ne(self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
150+
if let Some(other) = other.payload::<PyDict>() {
151+
let neq = !self.inner_eq(other, vm)?;
152+
Ok(vm.ctx.new_bool(neq))
153+
} else {
154+
Ok(vm.ctx.not_implemented())
155+
}
156+
}
157+
149158
fn len(self, _vm: &VirtualMachine) -> usize {
150159
self.entries.borrow().len()
151160
}
@@ -575,6 +584,7 @@ pub fn init(context: &PyContext) {
575584
"__contains__" => context.new_rustfunc(PyDictRef::contains),
576585
"__delitem__" => context.new_rustfunc(PyDictRef::inner_delitem),
577586
"__eq__" => context.new_rustfunc(PyDictRef::eq),
587+
"__ne__" => context.new_rustfunc(PyDictRef::ne),
578588
"__getitem__" => context.new_rustfunc(PyDictRef::inner_getitem),
579589
"__iter__" => context.new_rustfunc(PyDictRef::iter),
580590
(slot new) => PyDictRef::new,

vm/src/obj/objenumerate.rs

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -26,27 +26,28 @@ impl PyValue for PyEnumerate {
2626
}
2727
}
2828

29-
fn enumerate_new(
30-
cls: PyClassRef,
31-
iterable: PyObjectRef,
32-
start: OptionalArg<PyIntRef>,
33-
vm: &VirtualMachine,
34-
) -> PyResult<PyEnumerateRef> {
35-
let counter = match start {
36-
OptionalArg::Present(start) => start.as_bigint().clone(),
37-
OptionalArg::Missing => BigInt::zero(),
38-
};
29+
#[pyimpl]
30+
impl PyEnumerate {
31+
#[pyslot(new)]
32+
fn tp_new(
33+
cls: PyClassRef,
34+
iterable: PyObjectRef,
35+
start: OptionalArg<PyIntRef>,
36+
vm: &VirtualMachine,
37+
) -> PyResult<PyEnumerateRef> {
38+
let counter = match start {
39+
OptionalArg::Present(start) => start.as_bigint().clone(),
40+
OptionalArg::Missing => BigInt::zero(),
41+
};
3942

40-
let iterator = objiter::get_iter(vm, &iterable)?;
41-
PyEnumerate {
42-
counter: RefCell::new(counter.clone()),
43-
iterator,
43+
let iterator = objiter::get_iter(vm, &iterable)?;
44+
PyEnumerate {
45+
counter: RefCell::new(counter.clone()),
46+
iterator,
47+
}
48+
.into_ref_with_type(vm, cls)
4449
}
45-
.into_ref_with_type(vm, cls)
46-
}
4750

48-
#[pyimpl]
49-
impl PyEnumerate {
5051
#[pymethod(name = "__next__")]
5152
fn next(&self, vm: &VirtualMachine) -> PyResult {
5253
let iterator = &self.iterator;
@@ -69,7 +70,4 @@ impl PyEnumerate {
6970

7071
pub fn init(context: &PyContext) {
7172
PyEnumerate::extend_class(context, &context.types.enumerate_type);
72-
extend_class!(context, &context.types.enumerate_type, {
73-
(slot new) => enumerate_new,
74-
});
7573
}

vm/src/obj/objfilter.rs

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,24 @@ impl PyValue for PyFilter {
2424
}
2525
}
2626

27-
fn filter_new(
28-
cls: PyClassRef,
29-
function: PyObjectRef,
30-
iterable: PyObjectRef,
31-
vm: &VirtualMachine,
32-
) -> PyResult<PyFilterRef> {
33-
let iterator = objiter::get_iter(vm, &iterable)?;
27+
#[pyimpl]
28+
impl PyFilter {
29+
#[pyslot(new)]
30+
fn tp_new(
31+
cls: PyClassRef,
32+
function: PyObjectRef,
33+
iterable: PyObjectRef,
34+
vm: &VirtualMachine,
35+
) -> PyResult<PyFilterRef> {
36+
let iterator = objiter::get_iter(vm, &iterable)?;
3437

35-
PyFilter {
36-
predicate: function.clone(),
37-
iterator,
38+
PyFilter {
39+
predicate: function.clone(),
40+
iterator,
41+
}
42+
.into_ref_with_type(vm, cls)
3843
}
39-
.into_ref_with_type(vm, cls)
40-
}
4144

42-
#[pyimpl]
43-
impl PyFilter {
4445
#[pymethod(name = "__next__")]
4546
fn next(&self, vm: &VirtualMachine) -> PyResult {
4647
let predicate = &self.predicate;
@@ -68,7 +69,4 @@ impl PyFilter {
6869

6970
pub fn init(context: &PyContext) {
7071
PyFilter::extend_class(context, &context.types.filter_type);
71-
extend_class!(context, &context.types.filter_type, {
72-
(slot new) => filter_new,
73-
});
7472
}

0 commit comments

Comments
 (0)