Skip to content

Commit b7c03b4

Browse files
authored
Merge pull request RustPython#601 from RustPython/ellipsis
Add ellipsis syntax.
2 parents cb1b9d3 + 05929b3 commit b7c03b4

File tree

10 files changed

+67
-2
lines changed

10 files changed

+67
-2
lines changed

parser/src/ast.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ pub enum Expression {
217217
True,
218218
False,
219219
None,
220+
Ellipsis,
220221
}
221222

222223
impl Expression {
@@ -259,6 +260,7 @@ impl Expression {
259260
Lambda { .. } => "lambda",
260261
IfExpression { .. } => "conditional expression",
261262
True | False | None => "keyword",
263+
Ellipsis => "ellipsis",
262264
}
263265
}
264266
}

parser/src/lexer.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -993,8 +993,15 @@ where
993993
Some('.') => {
994994
let tok_start = self.get_pos();
995995
self.next_char();
996-
let tok_end = self.get_pos();
997-
return Some(Ok((tok_start, Tok::Dot, tok_end)));
996+
if let (Some('.'), Some('.')) = (&self.chr0, &self.chr1) {
997+
self.next_char();
998+
self.next_char();
999+
let tok_end = self.get_pos();
1000+
return Some(Ok((tok_start, Tok::Ellipsis, tok_end)));
1001+
} else {
1002+
let tok_end = self.get_pos();
1003+
return Some(Ok((tok_start, Tok::Dot, tok_end)));
1004+
}
9981005
}
9991006
Some('\n') => {
10001007
let tok_start = self.get_pos();

parser/src/python.lalrpop

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,7 @@ Atom: ast::Expression = {
839839
"True" => ast::Expression::True,
840840
"False" => ast::Expression::False,
841841
"None" => ast::Expression::None,
842+
"..." => ast::Expression::Ellipsis,
842843
};
843844

844845
TestListComp: Vec<ast::Expression> = {
@@ -1048,6 +1049,7 @@ extern {
10481049
"~" => lexer::Tok::Tilde,
10491050
":" => lexer::Tok::Colon,
10501051
"." => lexer::Tok::Dot,
1052+
"..." => lexer::Tok::Ellipsis,
10511053
"," => lexer::Tok::Comma,
10521054
"*" => lexer::Tok::Star,
10531055
"**" => lexer::Tok::DoubleStar,

tests/snippets/ellipsis.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
3+
a = ...
4+
b = ...
5+
c = type(a)() # Test singleton behavior
6+
7+
assert a is b
8+
assert b is c

vm/src/bytecode.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ pub enum Constant {
193193
Code { code: Box<CodeObject> },
194194
Tuple { elements: Vec<Constant> },
195195
None,
196+
Ellipsis,
196197
}
197198

198199
#[derive(Debug, Clone, PartialEq)]
@@ -385,6 +386,7 @@ impl fmt::Display for Constant {
385386
.join(", ")
386387
),
387388
Constant::None => write!(f, "None"),
389+
Constant::Ellipsis => write!(f, "Ellipsis"),
388390
}
389391
}
390392
}

vm/src/compile.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,6 +1056,11 @@ impl Compiler {
10561056
value: bytecode::Constant::None,
10571057
});
10581058
}
1059+
ast::Expression::Ellipsis => {
1060+
self.emit(Instruction::LoadConst {
1061+
value: bytecode::Constant::Ellipsis,
1062+
});
1063+
}
10591064
ast::Expression::String { value } => {
10601065
self.compile_string(value)?;
10611066
}

vm/src/obj/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ pub mod objbytes;
66
pub mod objcode;
77
pub mod objcomplex;
88
pub mod objdict;
9+
pub mod objellipsis;
910
pub mod objenumerate;
1011
pub mod objfilter;
1112
pub mod objfloat;

vm/src/obj/objellipsis.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use crate::pyobject::{PyContext, PyFuncArgs, PyResult, TypeProtocol};
2+
use crate::vm::VirtualMachine;
3+
4+
pub fn init(context: &PyContext) {
5+
let ellipsis_type = &context.ellipsis_type;
6+
context.set_attr(ellipsis_type, "__new__", context.new_rustfunc(ellipsis_new));
7+
context.set_attr(
8+
ellipsis_type,
9+
"__repr__",
10+
context.new_rustfunc(ellipsis_repr),
11+
);
12+
}
13+
14+
fn ellipsis_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
15+
arg_check!(vm, args, required = [(_cls, None)]);
16+
Ok(vm.ctx.ellipsis())
17+
}
18+
19+
fn ellipsis_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
20+
arg_check!(vm, args, required = [(_cls, None)]);
21+
Ok(vm.new_str("Ellipsis".to_string()))
22+
}

vm/src/pyobject.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use crate::obj::objbytes;
1919
use crate::obj::objcode;
2020
use crate::obj::objcomplex::{self, PyComplex};
2121
use crate::obj::objdict;
22+
use crate::obj::objellipsis;
2223
use crate::obj::objenumerate;
2324
use crate::obj::objfilter;
2425
use crate::obj::objfloat::{self, PyFloat};
@@ -115,6 +116,7 @@ pub struct PyContext {
115116
pub classmethod_type: PyObjectRef,
116117
pub code_type: PyObjectRef,
117118
pub dict_type: PyObjectRef,
119+
pub ellipsis_type: PyObjectRef,
118120
pub enumerate_type: PyObjectRef,
119121
pub filter_type: PyObjectRef,
120122
pub float_type: PyObjectRef,
@@ -130,6 +132,7 @@ pub struct PyContext {
130132
pub map_type: PyObjectRef,
131133
pub memoryview_type: PyObjectRef,
132134
pub none: PyObjectRef,
135+
pub ellipsis: PyObjectRef,
133136
pub not_implemented: PyObjectRef,
134137
pub tuple_type: PyObjectRef,
135138
pub set_type: PyObjectRef,
@@ -207,6 +210,7 @@ impl PyContext {
207210
let bytearray_type = create_type("bytearray", &type_type, &object_type, &dict_type);
208211
let tuple_type = create_type("tuple", &type_type, &object_type, &dict_type);
209212
let iter_type = create_type("iter", &type_type, &object_type, &dict_type);
213+
let ellipsis_type = create_type("EllipsisType", &type_type, &object_type, &dict_type);
210214
let enumerate_type = create_type("enumerate", &type_type, &object_type, &dict_type);
211215
let filter_type = create_type("filter", &type_type, &object_type, &dict_type);
212216
let map_type = create_type("map", &type_type, &object_type, &dict_type);
@@ -223,6 +227,8 @@ impl PyContext {
223227
create_type("NoneType", &type_type, &object_type, &dict_type),
224228
);
225229

230+
let ellipsis = PyObject::new(PyObjectPayload::None, ellipsis_type.clone());
231+
226232
let not_implemented = PyObject::new(
227233
PyObjectPayload::NotImplemented,
228234
create_type("NotImplementedType", &type_type, &object_type, &dict_type),
@@ -257,12 +263,14 @@ impl PyContext {
257263
false_value,
258264
tuple_type,
259265
iter_type,
266+
ellipsis_type,
260267
enumerate_type,
261268
filter_type,
262269
map_type,
263270
zip_type,
264271
dict_type,
265272
none,
273+
ellipsis,
266274
not_implemented,
267275
str_type,
268276
range_type,
@@ -300,6 +308,7 @@ impl PyContext {
300308
objsuper::init(&context);
301309
objtuple::init(&context);
302310
objiter::init(&context);
311+
objellipsis::init(&context);
303312
objenumerate::init(&context);
304313
objfilter::init(&context);
305314
objmap::init(&context);
@@ -441,6 +450,11 @@ impl PyContext {
441450
pub fn none(&self) -> PyObjectRef {
442451
self.none.clone()
443452
}
453+
454+
pub fn ellipsis(&self) -> PyObjectRef {
455+
self.ellipsis.clone()
456+
}
457+
444458
pub fn not_implemented(&self) -> PyObjectRef {
445459
self.not_implemented.clone()
446460
}
@@ -699,6 +713,7 @@ impl PyContext {
699713
self.new_tuple(elements)
700714
}
701715
bytecode::Constant::None => self.none(),
716+
bytecode::Constant::Ellipsis => self.ellipsis(),
702717
}
703718
}
704719
}

vm/src/stdlib/ast.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@ fn expression_to_ast(ctx: &PyContext, expression: &ast::Expression) -> PyObjectR
395395

396396
node
397397
}
398+
ast::Expression::Ellipsis => create_node(ctx, "Ellipsis"),
398399
ast::Expression::List { elements } => {
399400
let node = create_node(ctx, "List");
400401

0 commit comments

Comments
 (0)