Skip to content
Browse files

* lib/unholy/pyasm.rb: got some basic blocks working. slight work on…

… arrays.
  • Loading branch information...
1 parent d15375b commit d5266bb310536bd7899e9291bf05ddf1b79827fc _why committed May 15, 2008
Showing with 100 additions and 14 deletions.
  1. +1 −4 bin/unholy
  2. +7 −0 lib/unholy.rb
  3. +47 −10 lib/unholy/pyasm.rb
  4. +9 −0 python/Kernel.py
  5. +6 −0 tests/01puts.rb
  6. +3 −0 tests/02array.rb
  7. +5 −0 tests/03at.rb
  8. +3 −0 tests/04block.rb
  9. +19 −0 tests/all
View
5 bin/unholy
@@ -2,7 +2,4 @@
$: << "./lib"
require 'unholy'
-asm = Pyasm.new(ARGV[0])
-asm.import :Kernel
-asm.eval IO.read(ARGV[0])
-asm.compile(ARGV[0]+".pyc")
+unholy(ARGV[0], ARGV[0] + ".pyc")
View
7 lib/unholy.rb
@@ -1,3 +1,10 @@
require 'unholy/tuple'
require 'unholy/pickle'
require 'unholy/pyasm'
+
+def unholy(fname, fpyc)
+ asm = Pyasm.new(fname)
+ asm.import :Kernel
+ asm.eval IO.read(fname)
+ asm.compile(fpyc)
+end
View
57 lib/unholy/pyasm.rb
@@ -8,11 +8,11 @@ class Pyasm
:== => 2
}
- attr_accessor :argc, :nlocals, :stacksize, :flags, :consts, :bytecode,
+ attr_accessor :argc, :stacksize, :flags, :consts, :bytecode,
:filename, :lineno, :name, :symbols, :stacknow, :varsyms, :jumps, :labels, :lines
- def initialize(fname, type = nil, name = "<module>", lineno = 0)
- @argc, @nlocals, @stacksize, @flags, @filename, @lineno, @name, @stack, @nopop, @type =
- 0, 0, 1, CO_NOFREE, fname, lineno, name, [], 0, type
+ def initialize(fname, type = nil, name = "<module>", lineno = 0, argc = 0)
+ @argc, @stacksize, @flags, @filename, @lineno, @name, @stack, @nopop, @type =
+ argc, 1, CO_NOFREE, fname, lineno, name, [], 0, type
@flags |= CO_NEWLOCALS if [:class, :method].include?(type)
@consts = [-1, nil]
@symbols = [:Kernel]
@@ -49,11 +49,16 @@ def mark_jump n, bc
end
def pop_top; bc 0x01; dump_stack end
- def binary_add
- add = bc 0x17
+ def infix i
+ add = bc i
@stack.pop
add
end
+ def binary_add; infix 0x17 end
+ def binary_subscr; infix 0x19 end
+ def inplace_add; infix 0x37 end
+ def print_item; dump_stack; bc 0x47 end
+ def print_newline; dump_stack; bc 0x48 end
def load_locals; bc 0x52 end
def ret_val; bc 0x53 end
def build_class; bc 0x59 end
@@ -95,7 +100,7 @@ def jump_if_false(n)
mark_jump n, bc(0x6f, n, 0x0)
end
def load_fast(n)
- stack_push Object.new, bc(0x7c, n, 0x0)
+ stack_push n, bc(0x7c, n, 0x0)
end
def store_fast(n)
dump_stack
@@ -133,9 +138,16 @@ def getlocal id
def setlocal id
store_fast id - 2
end
+ def getdynamic id, lvl
+ load_name @varsyms[id - 1]
+ end
def getconstant sym
load_name(sym)
end
+ def print_obj
+ print_item
+ print_newline
+ end
def import(mod, inner = nil)
load_const(-1)
@@ -173,9 +185,22 @@ def leave
end
ret_val
end
+ def duparray ary
+ ary.each do |x|
+ load_const x
+ end
+ build_list ary.length
+ end
def newarray size
build_list size
end
+ def opt_aref
+ binary_subscr
+ end
+ def opt_ltlt
+ build_list 1
+ inplace_add
+ end
def opt_plus
binary_add
end
@@ -198,12 +223,16 @@ def message(meth, op_argc, blockiseq, op_flag, ic)
args = @stack[-op_argc, op_argc].map { |o,_| o }
idx = @bytecode.index { |x| x.object_id == recbytes.object_id }
bytes = []
+
if idx
bytes = @bytecode.slice! idx..-1
unless receiver
unpop
case meth
+ when :print
+ @bytecode += bytes
+ return print_obj
when :import
return import(*args)
when :from
@@ -226,6 +255,14 @@ def message(meth, op_argc, blockiseq, op_flag, ic)
load_attr(meth)
end
@bytecode += bytes
+
+ if blockiseq
+ blk = Pyasm.new(@filename, :block, "<block>", @lines.last[0])
+ blk.load_iseq blockiseq
+ load_const(blk)
+ op_argc += 1
+ end
+
call_func(op_argc)
end
def unpop
@@ -255,7 +292,7 @@ def define type, id, iseq, is_singleton
bytes = @bytecode.slice! idx..-1
bytes.shift unless receiver
- asm = Pyasm.new(@filename, type, id.to_s, @lines.last[0])
+ asm = Pyasm.new(@filename, type, id.to_s, @lines.last[0], iseq[5][:arg_size])
if type == :class
asm.load_name(:__name__)
asm.store_name(:__module__)
@@ -297,7 +334,7 @@ def load_iseq iseq
iseq = iseq.to_a
@varsyms += iseq[8].reverse
- iseq.last.each do |inst|
+ iseq[11].each do |inst|
case inst
when Integer # line no
line inst
@@ -332,7 +369,7 @@ def to_pickle
end
f = "c"
- f << [@argc, @nlocals, @stacksize, @flags].pack("LLLL")
+ f << [@argc, @varsyms.length, @stacksize, @flags].pack("LLLL")
# bytecode
bytes = @bytecode.flatten
View
9 python/Kernel.py
@@ -1,3 +1,12 @@
+class Proc:
+ def __init__(self, code):
+ self.code = code
+ def call(self, *args):
+ exec self.code in dict(zip(self.code.co_varnames, args))
+
+def proc(func):
+ return Proc(func)
+
def puts(*args):
for x in args: print x
if not args: print
View
6 tests/01puts.rb
@@ -0,0 +1,6 @@
+# Content-Type: text/plain
+#
+# Hello, world!
+puts "Content-Type: text/plain"
+puts
+puts "Hello, world!"
View
3 tests/02array.rb
@@ -0,0 +1,3 @@
+# [1, 2, 'c', 'd', [3, 4]]
+a = [ 1, 2 ] << "c" << "d" << [ 3, 4 ]
+print a
View
5 tests/03at.rb
@@ -0,0 +1,5 @@
+# 4
+# 5
+a = [1, 2, 3, 4, 5, 6]
+print a[3]
+print a[-2]
View
3 tests/04block.rb
@@ -0,0 +1,3 @@
+# 3
+a = proc { |x| print(x + 1) }
+a.call(2)
View
19 tests/all
@@ -0,0 +1,19 @@
+#!/usr/bin/env ruby
+$: << "./lib"
+require 'unholy'
+
+ENV['PYTHONPATH'] = 'python'
+
+`rm -rf tests/*.pyc`
+Dir["tests/*.rb"].each do |rb|
+ unholy(rb, rb + ".pyc")
+ expect = File.read(rb).scan(/^# (.+\n)|^#(\n)/).join
+ actual = `python #{rb}.pyc`
+ puts "#{rb}: #{expect == actual ? "passed" : "FAILED"}"
+ unless expect == actual
+ puts " expected:"
+ puts expect.gsub(/^/, ' ')
+ puts " actual:"
+ puts actual.gsub(/^/, ' ')
+ end
+end

0 comments on commit d5266bb

Please sign in to comment.
Something went wrong with that request. Please try again.