Skip to content

Commit 1d3db31

Browse files
Merge pull request #512 from RustPython/mod_dis
Mod dis
2 parents 7dfd8f0 + 5ebfd55 commit 1d3db31

File tree

4 files changed

+149
-11
lines changed

4 files changed

+149
-11
lines changed

tests/snippets/dismod.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import dis
2+
3+
dis.disassemble(compile("5 + x + 5 or 2", "", "eval"))
4+
print("\n")
5+
dis.disassemble(compile("def f(x):\n return 1", "", "exec"))
6+
print("\n")
7+
dis.disassemble(compile("if a:\n 1 or 2\nelif x == 'hello':\n 3\nelse:\n 4", "", "exec"))
8+
print("\n")
9+
dis.disassemble(compile("f(x=1, y=2)", "", "eval"))
10+
print("\n")

vm/src/bytecode.rs

Lines changed: 119 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
use num_bigint::BigInt;
99
use num_complex::Complex64;
1010
use rustpython_parser::ast;
11-
use std::collections::HashMap;
11+
use std::collections::{HashMap, HashSet};
1212
use std::fmt;
1313

1414
/// Primary container of a single code object. Each python function has
@@ -173,6 +173,8 @@ pub enum Instruction {
173173
},
174174
}
175175

176+
use self::Instruction::*;
177+
176178
#[derive(Debug, Clone, PartialEq)]
177179
pub enum CallType {
178180
Positional(usize),
@@ -277,17 +279,123 @@ impl CodeObject {
277279
}
278280
}
279281

282+
impl fmt::Display for CodeObject {
283+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
284+
let label_targets: HashSet<&usize> = self.label_map.values().collect();
285+
for (offset, instruction) in self.instructions.iter().enumerate() {
286+
let arrow = if label_targets.contains(&offset) {
287+
">>"
288+
} else {
289+
" "
290+
};
291+
write!(f, " {} {:5} ", arrow, offset)?;
292+
instruction.fmt_dis(f, &self.label_map)?;
293+
}
294+
Ok(())
295+
}
296+
}
297+
298+
impl Instruction {
299+
fn fmt_dis(&self, f: &mut fmt::Formatter, label_map: &HashMap<Label, usize>) -> fmt::Result {
300+
macro_rules! w {
301+
($variant:ident) => {
302+
write!(f, "{:20}\n", stringify!($variant))
303+
};
304+
($variant:ident, $var:expr) => {
305+
write!(f, "{:20} ({})\n", stringify!($variant), $var)
306+
};
307+
($variant:ident, $var1:expr, $var2:expr) => {
308+
write!(f, "{:20} ({}, {})\n", stringify!($variant), $var1, $var2)
309+
};
310+
}
311+
312+
match self {
313+
Import { name, symbol } => w!(Import, name, format!("{:?}", symbol)),
314+
ImportStar { name } => w!(ImportStar, name),
315+
LoadName { name } => w!(LoadName, name),
316+
StoreName { name } => w!(StoreName, name),
317+
DeleteName { name } => w!(DeleteName, name),
318+
StoreSubscript => w!(StoreSubscript),
319+
DeleteSubscript => w!(DeleteSubscript),
320+
StoreAttr { name } => w!(StoreAttr, name),
321+
DeleteAttr { name } => w!(DeleteAttr, name),
322+
LoadConst { value } => w!(LoadConst, value),
323+
UnaryOperation { op } => w!(UnaryOperation, format!("{:?}", op)),
324+
BinaryOperation { op, inplace } => w!(BinaryOperation, format!("{:?}", op), inplace),
325+
LoadAttr { name } => w!(LoadAttr, name),
326+
CompareOperation { op } => w!(CompareOperation, format!("{:?}", op)),
327+
Pop => w!(Pop),
328+
Rotate { amount } => w!(Rotate, amount),
329+
Duplicate => w!(Duplicate),
330+
GetIter => w!(GetIter),
331+
Pass => w!(Pass),
332+
Continue => w!(Continue),
333+
Break => w!(Break),
334+
Jump { target } => w!(Jump, label_map[target]),
335+
JumpIf { target } => w!(JumpIf, label_map[target]),
336+
JumpIfFalse { target } => w!(JumpIfFalse, label_map[target]),
337+
MakeFunction { flags } => w!(MakeFunction, format!("{:?}", flags)),
338+
CallFunction { typ } => w!(CallFunction, format!("{:?}", typ)),
339+
ForIter { target } => w!(ForIter, label_map[target]),
340+
ReturnValue => w!(ReturnValue),
341+
YieldValue => w!(YieldValue),
342+
YieldFrom => w!(YieldFrom),
343+
SetupLoop { start, end } => w!(SetupLoop, label_map[start], label_map[end]),
344+
SetupExcept { handler } => w!(SetupExcept, handler),
345+
SetupWith { end } => w!(SetupWith, end),
346+
CleanupWith { end } => w!(CleanupWith, end),
347+
PopBlock => w!(PopBlock),
348+
Raise { argc } => w!(Raise, argc),
349+
BuildString { size } => w!(BuildString, size),
350+
BuildTuple { size, unpack } => w!(BuildTuple, size, unpack),
351+
BuildList { size, unpack } => w!(BuildList, size, unpack),
352+
BuildSet { size, unpack } => w!(BuildSet, size, unpack),
353+
BuildMap { size, unpack } => w!(BuildMap, size, unpack),
354+
BuildSlice { size } => w!(BuildSlice, size),
355+
ListAppend { i } => w!(ListAppend, i),
356+
SetAdd { i } => w!(SetAdd, i),
357+
MapAdd { i } => w!(MapAdd, i),
358+
PrintExpr => w!(PrintExpr),
359+
LoadBuildClass => w!(LoadBuildClass),
360+
StoreLocals => w!(StoreLocals),
361+
UnpackSequence { size } => w!(UnpackSequence, size),
362+
UnpackEx { before, after } => w!(UnpackEx, before, after),
363+
Unpack => w!(Unpack),
364+
FormatValue { spec } => w!(FormatValue, spec),
365+
}
366+
}
367+
}
368+
369+
impl fmt::Display for Constant {
370+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
371+
match self {
372+
Constant::Integer { value } => write!(f, "{}", value),
373+
Constant::Float { value } => write!(f, "{}", value),
374+
Constant::Complex { value } => write!(f, "{}", value),
375+
Constant::Boolean { value } => write!(f, "{}", value),
376+
Constant::String { value } => write!(f, "{:?}", value),
377+
Constant::Bytes { value } => write!(f, "{:?}", value),
378+
Constant::Code { code } => write!(f, "{:?}", code),
379+
Constant::Tuple { elements } => write!(
380+
f,
381+
"({})",
382+
elements
383+
.iter()
384+
.map(|e| format!("{}", e))
385+
.collect::<Vec<_>>()
386+
.join(", ")
387+
),
388+
Constant::None => write!(f, "None"),
389+
}
390+
}
391+
}
392+
280393
impl fmt::Debug for CodeObject {
281394
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
282-
let inst_str = self
283-
.instructions
284-
.iter()
285-
.zip(self.locations.iter())
286-
.enumerate()
287-
.map(|(i, inst)| format!("Inst {}: {:?}", i, inst))
288-
.collect::<Vec<_>>()
289-
.join("\n");
290-
let labelmap_str = format!("label_map: {:?}", self.label_map);
291-
write!(f, "Code Object {{ \n{}\n{} }}", inst_str, labelmap_str)
395+
write!(
396+
f,
397+
"<code object {} at ??? file {:?}, line {}>",
398+
self.obj_name, self.source_path, self.first_line_number
399+
)
292400
}
293401
}

vm/src/stdlib/dis.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use super::super::obj::objcode;
2+
use super::super::obj::objtype;
3+
use super::super::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol};
4+
use super::super::vm::VirtualMachine;
5+
6+
fn dis_disassemble(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
7+
arg_check!(vm, args, required = [(co, Some(vm.ctx.code_type()))]);
8+
9+
let code = objcode::get_value(co);
10+
print!("{}", code);
11+
Ok(vm.get_none())
12+
}
13+
14+
pub fn mk_module(ctx: &PyContext) -> PyObjectRef {
15+
let py_mod = ctx.new_module("dis", ctx.new_scope(None));
16+
ctx.set_attr(&py_mod, "disassemble", ctx.new_rustfunc(dis_disassemble));
17+
py_mod
18+
}

vm/src/stdlib/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
mod ast;
2+
mod dis;
23
pub mod io;
34
mod json;
45
mod keyword;
@@ -21,6 +22,7 @@ pub type StdlibInitFunc = fn(&PyContext) -> PyObjectRef;
2122
pub fn get_module_inits() -> HashMap<String, StdlibInitFunc> {
2223
let mut modules = HashMap::new();
2324
modules.insert("ast".to_string(), ast::mk_module as StdlibInitFunc);
25+
modules.insert("dis".to_string(), dis::mk_module as StdlibInitFunc);
2426
modules.insert("io".to_string(), io::mk_module as StdlibInitFunc);
2527
modules.insert("json".to_string(), json::mk_module as StdlibInitFunc);
2628
modules.insert("keyword".to_string(), keyword::mk_module as StdlibInitFunc);

0 commit comments

Comments
 (0)