Created
January 3, 2017 08:31
-
-
Save smcl/6baa175bc2c337cc6446680c2e7015ae to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
ipy.py | |
This is a fairly nastily hacked together piece of code to produce a visualisation of the execution | |
of a simple python application IronPython. It uses PIL to produce a series of PNG files in a | |
directory ./out which each have a listing of instructions, stack, globals and output for the | |
ipy vm. | |
""" | |
import sys | |
from PIL import Image, ImageDraw, ImageFont | |
mode = "RGBA" | |
size = (710, 600) | |
color = "white" | |
class Instruction(object): | |
def __init__(self, instruction, stack, global_objects, comment, output): | |
self.instruction = instruction | |
self.stack = stack | |
self.global_objects = global_objects | |
self.comment = comment | |
self.output = output | |
def create_image_from_instr(instructions, current_instr): | |
# setup new image file + values/constants | |
im = Image.new(mode, size, color) | |
draw = ImageDraw.Draw(im) | |
row_height = 20 | |
font = ImageFont.truetype("SourceCodePro-Regular.ttf", row_height - 2) | |
boldfont = ImageFont.truetype("SourceCodePro-Bold.ttf", row_height - 2) | |
#################################################### | |
# plot the main instr window | |
instr_pad = 10 | |
instr_box = [ | |
(instr_pad, instr_pad), | |
(300, 600 - instr_pad) | |
] | |
# draw the outline | |
draw.rectangle(instr_box, None, "black") | |
# draw title of instructions window | |
instr_title_box = [ | |
(instr_pad, instr_pad), | |
(300, instr_pad + row_height) | |
] | |
draw.rectangle(instr_title_box, "black", None) | |
draw.text((instr_pad,instr_pad), "Instructions", fill="white", font=boldfont) | |
# highlight an instruction | |
current_instr_start_y = row_height + instr_pad + (current_instr * row_height) | |
current_instr_box = [ | |
(instr_pad, current_instr_start_y), | |
(300, current_instr_start_y + row_height) | |
] | |
draw.rectangle(current_instr_box, "red", None) | |
# fill the outline | |
for i, instr in enumerate(instructions): | |
y = row_height + instr_pad + (i * row_height) | |
if i == current_instr: | |
draw.text((instr_pad + instr_pad, y), instr.instruction, fill="white", font=font) | |
else: | |
draw.text((instr_pad + instr_pad, y), instr.instruction, fill="black", font=font) | |
#################################################### | |
# plot the stack window | |
stack_box = [ | |
(300 + instr_pad, instr_pad), | |
(700, 180 - instr_pad) | |
] | |
draw.rectangle(stack_box, None, "black") | |
stack_title_box = [ | |
(300 + instr_pad, instr_pad), | |
(700, instr_pad + row_height) | |
] | |
draw.rectangle(stack_title_box, "black", None) | |
draw.text((300 + instr_pad, instr_pad), "Stack", fill="white", font=boldfont) | |
# fill the outline | |
#for i, stack in enumerate(instructions[current_instr].stack): | |
# y = row_height + instr_pad + (i * row_height) | |
for i, stack in enumerate(instructions[current_instr].stack[::-1]): | |
y = 180 - row_height - row_height - (i * row_height) | |
draw.text(((300 + instr_pad + instr_pad), y), str(stack), fill="black", font=font) | |
#################################################### | |
# plot the global window | |
global_box = [ | |
(300 + instr_pad, 180), | |
(700 , 300 - instr_pad) | |
] | |
draw.rectangle(global_box, None, "black") | |
globals_title_box = [ | |
(300 + instr_pad, 180), | |
(700, 180 + row_height) | |
] | |
draw.rectangle(globals_title_box, "black", None) | |
draw.text((300 + instr_pad, 180), "Globals", fill="white", font=boldfont) | |
# fill the outline | |
for i, key in enumerate(instructions[current_instr].global_objects.keys()): | |
y = 180 + row_height + (i * row_height) | |
draw.text(((300 + instr_pad + instr_pad), y), "%s ---> %s" % (key, instructions[current_instr].global_objects[key]), fill="black", font=font) | |
#################################################### | |
# plot the "comment" window | |
comment_box = [ | |
(300 + instr_pad, 300), | |
(700, 450) | |
] | |
comment_title_box = [ | |
(300 + instr_pad, 300), | |
(700, 300 + row_height) | |
] | |
draw.rectangle(comment_title_box, "black", None) | |
draw.text((300 + instr_pad, 300), "Comment", fill="white", font=boldfont) | |
draw.rectangle(comment_box, None, "black") | |
draw.multiline_text((300 + instr_pad + instr_pad, 300 + row_height), instructions[current_instr].comment, font=font, fill="black") | |
#################################################### | |
# plot the output window | |
output_box = [ | |
(300 + instr_pad, 450 + instr_pad), | |
(700, 600 - instr_pad) | |
] | |
output_title_box = [ | |
(300 + instr_pad, 450 + instr_pad), | |
(700, 450 + instr_pad + row_height) | |
] | |
draw.rectangle(output_title_box, "black", None) | |
draw.text((300 + instr_pad, 450 + instr_pad), "Output", fill="white", font=boldfont) | |
draw.rectangle(output_box, None, "black") | |
draw.multiline_text((300 + instr_pad + instr_pad, 450 + instr_pad + row_height), instructions[current_instr].output, font=font, fill="black") | |
#################################################### | |
# dump the file | |
im.save("./out/%s.PNG" % (str(current_instr).zfill(3))) | |
stack = [ | |
] | |
# let's initialise the instructions | |
test_py_instrs = [ | |
# setting up x | |
Instruction("LoadObject(1)", ["null", "false", "null", "module: \"__main__\"", "{IronPython.RunTime.FunctionCode}"], {}, "Push 1 to the stack", ""), | |
Instruction("StoreLocal", [1,"null", "false", "null", "module: \"__main__\"", "{IronPython.RunTime.FunctionCode}"], {}, "Update a Local to value @ top of\nstack. Think this is the count\nof local variables.", ""), | |
Instruction("LoadObject(10)", ["null", "false", "1", "module: \"__main__\"", "{IronPython.RunTime.FunctionCode}"], {}, "Push 10 to the stack", ""), | |
Instruction("SetGlobal(x)", [ "10", "null", "false", "1", "module: \"__main__\"", "{IronPython.RunTime.FunctionCode}" ], {}, "Set x to value @ top of stack", ""), | |
Instruction("Pop", [ "10", "null", "false", "1", "module: \"__main__\"", "{IronPython.RunTime.FunctionCode}" ], { "x" : "10" }, "Remove value from stack", ""), | |
# setting up y | |
Instruction("LoadObject(2)", ["null", "false", "1", "module: \"__main__\"", "{IronPython.RunTime.FunctionCode}"], { "x" : "10" }, "Push 2 to the stack", ""), | |
Instruction("StoreLocal", [2, "null", "false", "1", "module: \"__main__\"", "{IronPython.RunTime.FunctionCode}"], { "x" : "10" }, "Pop & update local", ""), | |
Instruction("LoadObject(20)", ["null", "false", "2", "module: \"__main__\"", "{IronPython.RunTime.FunctionCode}"], { "x" : "10" }, "Push 20 to the stack", ""), | |
Instruction("SetGlobal(y)", [ "20", "null", "false", "2", "module: \"__main__\"", "{IronPython.RunTime.FunctionCode}" ], { "x" : "10" }, "Set y to value @ top of stack", ""), | |
Instruction("Pop", [ "20","null", "false", "2", "module: \"__main__\"", "{IronPython.RunTime.FunctionCode}" ], { "x" : "10", "y" : "20" }, "Remove value from stack", ""), | |
# x + y | |
Instruction("LoadObject(3)", ["null", "false", "2", "module: \"__main__\"", "{IronPython.RunTime.FunctionCode}"], { "x" : "10", "y" : "20" }, "Push 3 to the stack", ""), | |
Instruction("StoreLocal", [3,"null", "false", "2", "module: \"__main__\"", "{IronPython.RunTime.FunctionCode}"], { "x" : "10", "y" : "20" }, "Pop & update local", ""), | |
Instruction("GetGlobal(x)", ["null", "false", "3", "module: \"__main__\"", "{IronPython.RunTime.FunctionCode}"] , { "x" : "10", "y" : "20" }, "Get value of x and push to stack\ntop", ""), | |
Instruction("GetGlobal(y)", [ 10,"false", "3", "module: \"__main__\"", "{IronPython.RunTime.FunctionCode}" ], { "x" : "10", "y" : "20" }, "Get value of y and push to stack\ntop", ""), | |
Instruction("Dynamic(PythonBinary.Add)", [ 20, 10,"false", "3", "module: \"__main__\"", "{IronPython.RunTime.FunctionCode}" ], { "x" : "10", "y" : "20" }, "Take top two values of stack, add \nthem, remove them and push result", ""), | |
# store result in z | |
Instruction("SetGlobal(z)", [ 30, "false", "3", "module: \"__main__\"", "{IronPython.RunTime.FunctionCode}" ], { "x" : "10", "y" : "20" }, "Set z to value @ top of stack", ""), | |
Instruction("Pop", [ 30, "false", "3", "module: \"__main__\"", "{IronPython.RunTime.FunctionCode}" ], { "x" : "10", "y" : "20", "z" : "30" }, "Remove value from stack", ""), | |
Instruction("GetGlobal(z)", ["false", "3", "module: \"__main__\"", "{IronPython.RunTime.FunctionCode}"], { "x" : "10", "y" : "20", "z" : "30" }, "Get value of z and push to stack\ntop", ""), | |
Instruction("Call(Print)", [30,"false", "3", "module: \"__main__\"", "{IronPython.RunTime.FunctionCode}"], { "x" : "10", "y" : "20", "z" : "30" }, "Print top of stack to stdout", ""), | |
Instruction("", [30,"false", "3", "module: \"__main__\"", "{IronPython.RunTime.FunctionCode}"], { "x" : "10", "y" : "20", "z" : "30" }, "End of example.", "30") | |
] | |
for i, instr in enumerate(test_py_instrs): | |
create_image_from_instr(test_py_instrs, i) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment