Skip to content

Instantly share code, notes, and snippets.

@smcl
Created January 3, 2017 08:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save smcl/6baa175bc2c337cc6446680c2e7015ae to your computer and use it in GitHub Desktop.
Save smcl/6baa175bc2c337cc6446680c2e7015ae to your computer and use it in GitHub Desktop.
"""
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", ""),
# print
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