view test.py @ 0:e985e6d762b9 default tip

Origination.
author Atul Varma <varmaa@toolness.com>
date Wed, 24 Sep 2008 16:47:18 -0700
parents
children
line wrap: on
line source

import sys
import os
import tempfile
import subprocess
import dis

import json

def disassemble(co, lasti=-1):
    """Disassemble a code object and return a JSON-able dictionary
    of its representation.  This function is a slightly modified version
    of dis.disassemble()."""

    code = co.co_code
    labels = dis.findlabels(code)
    linestarts = dict(dis.findlinestarts(co))
    n = len(code)
    i = 0
    extended_arg = 0
    free = None

    op_infos = []
    bytes_to_op_infos = {}

    while i < n:
        op_info = {}
        op_infos.append(op_info)
        bytes_to_op_infos[i] = len(op_infos) - 1

        c = code[i]
        op = ord(c)
        if i in linestarts:
            op_info['line'] = linestarts[i]

        op_info['op'] = dis.opname[op]
        i = i+1
        if op >= dis.HAVE_ARGUMENT:
            oparg = ord(code[i]) + ord(code[i+1])*256 + extended_arg
            extended_arg = 0
            i = i+2
            if op == dis.EXTENDED_ARG:
                extended_arg = oparg*65536L
            op_info['arg'] = oparg

    return {'ops': op_infos,
            'bytes_to_ops': bytes_to_op_infos}

def exec_js(code, extra_output=None):
    if extra_output is None:
        extra_output = {}

    fd, temppath = tempfile.mkstemp('.js')
    os.close(fd)
    temp = open(temppath, 'w')
    temp.write(code.encode('utf-8'))
    temp.close()

    extra_output['errors'] = []

    BRANCH_LIMIT = '500'
    OUTPUT_FILENAME = '__temp_output.txt'
    ERROR_FILENAME = '__temp_input.txt'

    out_file = open(OUTPUT_FILENAME, 'w')
    err_file = open(ERROR_FILENAME, 'w')

    args = ['js',
            '-b', BRANCH_LIMIT,
            '-f', 'json2.js',
            '-f', 'py.js',
            '-f', temppath,
            '-f', 'post.js']

    popen = subprocess.Popen(args,
                             stdout=out_file,
                             stderr=err_file)

    popen.wait()

    os.remove(temppath)

    out_file = open(OUTPUT_FILENAME, 'r')
    output = out_file.read()

    err_file = open(ERROR_FILENAME, 'r')
    error = err_file.read()

    out_file.close()
    err_file.close()

    os.remove(OUTPUT_FILENAME)
    os.remove(ERROR_FILENAME)

    output = output.strip()

    if error:
        extra_output['errors'].append(error)

    try:
        obj = json.read(output)
    except Exception, e:
        extra_output['errors'].append(str(e))
        obj = None

    return obj

def run(pycode):
    bytecode = compile(pycode, "<string>", "exec")
    jsoncode = {'co_consts': bytecode.co_consts,
                'co_names': bytecode.co_names,
                'co_code': disassemble(bytecode)}
    extra = {}
    retval = exec_js('jsoncode = %s' % json.write(jsoncode), extra)
    if extra['errors']:
        print "Errors occurred: "
        print
        for error in extra['errors']:
            print "  * %s" % error,
        print
        print
        print "Disassembly of code:"
        print
        dis.dis(bytecode)
        raise Exception()
    return retval

def test_assignment_works():
    """
    >>> run('a = 1')['locals']['a']
    1
    """

    pass

def test_binary_addition_works():
    """
    >>> run('a = 1; a = 5 + a')['locals']['a']
    6
    """

    pass

def test_global_works():
    """
    >>> run('global a; a = 1')['globals']['a']
    1
    """

    pass

if __name__ == '__main__':
    import doctest
    doctest.testmod()