Skip to content

Commit ea0e25f

Browse files
Merge pull request RustPython#12 from cthulahoops/lambdas
Lambdas and pass arguments to functions.
2 parents fd44529 + b917efa commit ea0e25f

6 files changed

Lines changed: 72 additions & 7 deletions

File tree

parser/src/ast.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ pub enum Expression {
133133
Identifier {
134134
name: String,
135135
},
136+
Lambda {
137+
args: Vec<String>,
138+
body: Box<Expression>,
139+
},
136140
True,
137141
False,
138142
None,

parser/src/parser.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,4 +150,28 @@ mod tests {
150150
}
151151
);
152152
}
153+
154+
#[test]
155+
fn test_parse_lambda() {
156+
let source = String::from("lambda x, y: x * y\n"); // lambda(x, y): x * y");
157+
let parse_ast = parse_statement(&source);
158+
assert_eq!(
159+
parse_ast,
160+
Ok(ast::Statement::Expression {
161+
expression: ast::Expression::Lambda {
162+
args: vec![String::from("x"), String::from("y")],
163+
body:
164+
Box::new(ast::Expression::Binop {
165+
a: Box::new(ast::Expression::Identifier {
166+
name: String::from("x"),
167+
}),
168+
op: ast::Operator::Mult,
169+
b: Box::new(ast::Expression::Identifier {
170+
name: String::from("y"),
171+
})
172+
})
173+
}
174+
})
175+
)
176+
}
153177
}

parser/src/python.lalrpop

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,11 @@ FuncDef: ast::Statement = {
169169
};
170170

171171
Parameters: Vec<String> = {
172-
"(" <a: Comma<Identifier>> ")" => a,
172+
"(" <a: TypedArgsList> ")" => a,
173+
};
174+
175+
TypedArgsList: Vec<String> = {
176+
<a: Comma<Identifier>> => a,
173177
};
174178

175179
ClassDef: ast::Statement = {
@@ -178,8 +182,17 @@ ClassDef: ast::Statement = {
178182

179183
Test: ast::Expression = {
180184
<e:OrTest> => e,
185+
<e:LambdaDef> => e,
181186
};
182187

188+
LambdaDef: ast::Expression = {
189+
"lambda" <p:TypedArgsList> ":" <b:Expression> =>
190+
ast::Expression::Lambda {
191+
args:p,
192+
body:Box::new(b)
193+
}
194+
}
195+
183196
OrTest: ast::Expression = {
184197
<e:AndTest> => e,
185198
<e1:OrTest> "or" <e2:AndTest> => ast::Expression::BoolOp { a: Box::new(e1), op: ast::BooleanOperator::Or, b: Box::new(e2) },
@@ -410,6 +423,7 @@ extern {
410423
"return" => lexer::Tok::Return,
411424
"while" => lexer::Tok::While,
412425
"with" => lexer::Tok::With,
426+
"lambda" => lexer::Tok::Lambda,
413427
"True" => lexer::Tok::True,
414428
"False" => lexer::Tok::False,
415429
"None" => lexer::Tok::None,

vm/src/bytecode.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@ use std::fmt;
1717
pub struct CodeObject {
1818
pub instructions: Vec<Instruction>,
1919
pub label_map: HashMap<Label, usize>,
20+
pub arg_names: Vec<String>,
2021
}
2122

2223
impl CodeObject {
23-
pub fn new() -> CodeObject {
24+
pub fn new(arg_names : Vec<String>) -> CodeObject {
2425
CodeObject {
2526
instructions: Vec::new(),
2627
label_map: HashMap::new(),
28+
arg_names: arg_names,
2729
}
2830
}
2931
}

vm/src/compile.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ struct Compiler {
1515

1616
pub fn compile(rt: &mut Executor, source: &String, mode: Mode) -> Result<PyObjectRef, String> {
1717
let mut compiler = Compiler::new();
18-
compiler.push_code_object(CodeObject::new());
18+
compiler.push_code_object(CodeObject::new(Vec::new()));
1919
match mode {
2020
Mode::Exec => match parser::parse_program(source) {
2121
Ok(ast) => {
@@ -62,7 +62,7 @@ impl Compiler {
6262
}
6363

6464
fn push_code_object(&mut self, code_object: CodeObject) {
65-
self.code_object_stack.push(CodeObject::new());
65+
self.code_object_stack.push(CodeObject::new(Vec::new()));
6666
}
6767

6868
fn pop_code_object(&mut self) -> CodeObject {
@@ -191,7 +191,7 @@ impl Compiler {
191191
}
192192
ast::Statement::FunctionDef { name, args, body } => {
193193
// Create bytecode for this function:
194-
self.code_object_stack.push(CodeObject::new());
194+
self.code_object_stack.push(CodeObject::new(args.to_vec()));
195195
self.compile_statements(body);
196196
let code = self.code_object_stack.pop().unwrap();
197197
self.emit(Instruction::LoadConst {
@@ -444,6 +444,22 @@ impl Compiler {
444444
name: name.to_string(),
445445
});
446446
}
447+
ast::Expression::Lambda { args, body } => {
448+
self.code_object_stack.push(CodeObject::new(args.to_vec()));
449+
self.compile_expression(body);
450+
self.emit(Instruction::ReturnValue);
451+
let code = self.code_object_stack.pop().unwrap();
452+
self.emit(Instruction::LoadConst {
453+
value: bytecode::Constant::Code { code: code },
454+
});
455+
self.emit(Instruction::LoadConst {
456+
value: bytecode::Constant::String {
457+
value: String::from("<lambda>"),
458+
},
459+
});
460+
// Turn code object into function object:
461+
self.emit(Instruction::MakeFunction);
462+
}
447463
}
448464
}
449465

vm/src/vm.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use std::ops::Deref;
1010

1111
use super::builtins;
1212
use super::bytecode;
13-
use super::frame::{Block, Frame};
13+
use super::frame::{Block, Frame, copy_code};
1414
use super::import::import;
1515
use super::objlist;
1616
use super::objstr;
@@ -431,7 +431,12 @@ impl VirtualMachine {
431431
match f.kind {
432432
PyObjectKind::RustFunction { ref function } => f.call(self, args),
433433
PyObjectKind::Function { ref code } => {
434-
let frame = Frame::new(code.clone(), HashMap::new(), self.new_dict());
434+
let mut locals = self.new_dict();
435+
let code_object = copy_code(code.clone());
436+
for (name, value) in code_object.arg_names.iter().zip(args) {
437+
locals.set_item(name, value);
438+
}
439+
let frame = Frame::new(code.clone(), HashMap::new(), locals);
435440
self.run_frame(frame)
436441
}
437442
PyObjectKind::Class { name: _ } => self.new_instance(func_ref.clone(), args),

0 commit comments

Comments
 (0)