ruby-perl 0.99.15j

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,10 @@
1
+ require 'perl/value/scalar'
2
+
3
+ class String
4
+ #
5
+ # Returns a pointer suitable for passing to Perl.
6
+ #
7
+ def to_perl
8
+ Perl::Value::Scalar.to_perl(self)
9
+ end
10
+ end
@@ -0,0 +1,65 @@
1
+ module Perl
2
+ module FFILib
3
+ def self.included(klass)
4
+ klass.instance_eval do
5
+ require 'perl/internal'
6
+ extend FFI::Library
7
+
8
+ klass.ffi_lib '/System/Library/Perl/5.10.0/darwin-thread-multi-2level/CORE/libperl.dylib'
9
+
10
+ # PERL_SYS_INIT3()
11
+ attach_function 'Perl_sys_init3', [:int, :pointer, :pointer], :void
12
+ # PERL_SYS_TERM()
13
+ attach_function 'Perl_sys_term', [], :void
14
+
15
+ klass.attach_function 'perl_alloc', [], :pointer
16
+ attach_function 'perl_construct', [:pointer], :void
17
+ # PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
18
+ attach_function 'perl_parse', [:pointer, :pointer, :int, :pointer, :pointer], :void
19
+ attach_function 'perl_run', [:pointer], :void
20
+ attach_function 'perl_destruct', [:pointer], :void
21
+ attach_function 'perl_free', [:pointer], :void
22
+
23
+ # eval_pv()
24
+ attach_function 'Perl_eval_pv', [:pointer, :string, :int], :pointer
25
+ # call_pv()
26
+ attach_function 'Perl_call_pv', [:pointer, :string, :int], :int
27
+ # call_sv()
28
+ attach_function 'Perl_call_sv', [:pointer, :pointer, :int], :int
29
+
30
+ # ENTER()
31
+ attach_function 'Perl_push_scope', [:pointer], :void
32
+ # SAVETMPS()
33
+ attach_function 'Perl_save_int', [:pointer, :pointer], :void
34
+ # FREETMPS()
35
+ attach_function 'Perl_free_tmps', [:pointer], :void
36
+ # LEAVE()
37
+ attach_function 'Perl_pop_scope', [:pointer], :void
38
+ # PUSHMARK()
39
+ attach_function 'Perl_markstack_grow', [:pointer], :void
40
+
41
+ # newSV()
42
+ attach_function 'Perl_newSVpv', [:pointer, :string, :int], :pointer
43
+
44
+ attach_function 'Perl_newRV_noinc', [:pointer, :pointer], :pointer
45
+ attach_function 'Perl_sv_2mortal', [:pointer, :pointer], :pointer
46
+
47
+ attach_function 'Perl_newHV', [:pointer], :pointer
48
+ # hv_store()
49
+ attach_function 'Perl_hv_common_key_len', [:pointer, :pointer, :string, :int32, :int, :pointer, :uint32], :pointer
50
+
51
+ attach_variable 'PL_curinterp', :pointer
52
+
53
+ #
54
+ # Returns a reference to internal information on the current
55
+ # interpreter. Much of the public Perl API is in fact a thin
56
+ # wrapper over data contained in here. A lot of damage can be
57
+ # done my manipulating it incorrectly, so be careful.
58
+ #
59
+ def curinterp
60
+ Perl::Internal.new(Perl.PL_curinterp)
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,73 @@
1
+ module Perl
2
+ class Internal < FFI::Struct
3
+ class Stat < FFI::Struct
4
+ size = 144
5
+ layout :a, :pointer
6
+ end
7
+
8
+ class Tms < FFI::Struct
9
+ size = 32
10
+ layout :a, :pointer
11
+ end
12
+
13
+ class Jmpenv < FFI::Struct
14
+ size = 168
15
+ layout :a, :pointer
16
+ end
17
+
18
+ layout :Istack_sp, :pointer,
19
+ :Iopsave, :pointer,
20
+ :Icurpad, :pointer,
21
+ :Istack_base, :pointer,
22
+ :Istack_max, :pointer,
23
+ :Iscopestack, :pointer,
24
+ :Iscopestack_ix, :int32,
25
+ :Iscopestack_max, :int32,
26
+ :Isavestack, :pointer,
27
+ :Isavestack_ix, :int32,
28
+ :Isavestack_max, :int32,
29
+ :Itmps_stack, :pointer,
30
+ :Itmps_ix, :int32,
31
+ :Itmps_floor, :int32,
32
+ :Itmps_max, :int32,
33
+ :Imodcount, :int32,
34
+ :Imarkstack, :pointer,
35
+ :Imarkstack_ptr, :pointer,
36
+ :Imarkstack_max, :pointer,
37
+ :ISv, :pointer,
38
+ :IXpv, :pointer,
39
+ :Ina, :int,
40
+ :Istatbuf, Stat, # FIXME that's just wrong
41
+ :Istatcache, Stat, 288, # FIXME that's just wrong
42
+ :Istatgv, :pointer, 432,
43
+ :Istatname, :pointer,
44
+ :Itimesbuf, Tms, # FIXME that's just wrong
45
+ :Icurpm, :pointer, 480,
46
+ :Irs, :pointer,
47
+ :Ilast_in_gv, :pointer,
48
+ :Iofs_sv, :pointer,
49
+ :Idefoutgv, :pointer,
50
+ :Ichopset, :string,
51
+ :Iformtarget, :pointer,
52
+ :Ibodytarget, :pointer,
53
+ :Itoptarget, :pointer,
54
+ :Idefstash, :pointer,
55
+ :Icurstash, :pointer,
56
+ :Irestartop, :pointer,
57
+ :Icurcop, :pointer,
58
+ :Icurstack, :pointer,
59
+ :Icurstackinfo, :pointer,
60
+ :Imainstack, :pointer,
61
+ :Itop_env, :pointer,
62
+ :Istart_env, Jmpenv, # FIXME that's just wrong
63
+ :Ierrors, :pointer, 784,
64
+ :Ihv_fetch_ent_mh, :pointer,
65
+ :Ilastgotoprobe, :pointer,
66
+ :Isortcop, :pointer,
67
+ :Isortstash, :pointer,
68
+ :Ifirstgv, :pointer,
69
+ :Isecondgv, :pointer,
70
+ # TODO more stuff here
71
+ :Iexit_flags, :uint8, 1245
72
+ end
73
+ end
@@ -0,0 +1,89 @@
1
+ require 'perl'
2
+ require 'perl/common'
3
+ require 'perl/stack'
4
+
5
+ module Perl
6
+ class Interpreter
7
+ include Perl::Common
8
+
9
+ G_SCALAR = 0
10
+ G_ARRAY = 1
11
+ G_DISCARD = 2
12
+ G_EVAL = 4
13
+ G_NOARGS = 8
14
+ G_KEEPERR = 16
15
+ G_NODEBUG = 32
16
+ G_METHOD = 64
17
+ G_VOID = 128
18
+
19
+ def initialize
20
+ start
21
+ end
22
+
23
+ def eval(str=nil, &block)
24
+ return Perl.Perl_eval_pv(Perl.PL_curinterp, str, 1) if str
25
+
26
+ if block_given?
27
+ yield(Statement.new)
28
+ end
29
+ end
30
+ alias_method :run, :eval
31
+
32
+ def load(filename)
33
+ file = File.read(filename)
34
+ eval(file)
35
+ end
36
+
37
+ def call(method_name, args, return_type)
38
+ Perl::Stack.function_stack(args) do |stack|
39
+ rc = do_call(method_name, options_for_call(args, return_type))
40
+ ret = handle_return(rc, return_type, stack)
41
+
42
+ if return_type == :void
43
+ return nil
44
+ else
45
+ if block_given?
46
+ return yield(ret)
47
+ else
48
+ ret.freeze!
49
+ return ret
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ protected
56
+ def do_call(method_name, options)
57
+ method = method_name.is_a?(String) ? :Perl_call_pv : :Perl_call_sv
58
+ Perl.send(method, Perl.PL_curinterp, method_name, options)
59
+ end
60
+
61
+ # XXX should we have G_DISCARD ?
62
+ def options_for_call(args, return_type)
63
+ options = G_EVAL
64
+ options |= G_NOARGS if args.empty?
65
+
66
+ case return_type
67
+ when :list
68
+ options |= G_ARRAY
69
+ when :scalar
70
+ options |= G_SCALAR
71
+ when :void
72
+ options |= G_VOID
73
+ else
74
+ raise "Unknown return type #{return_type}"
75
+ end
76
+ end
77
+
78
+ def handle_return(ret, return_type, stack)
79
+ case return_type
80
+ when :list
81
+ when :scalar
82
+ raise "Unexpected ret=#{ret}" unless ret == 1
83
+ Perl::Value::Scalar.new(stack.pop_scalar)
84
+ when :void
85
+ raise "Unexpected ret=#{ret}" unless ret == 0
86
+ end
87
+ end
88
+ end
89
+ end
data/lib/perl/rack.rb ADDED
@@ -0,0 +1,45 @@
1
+ require 'perl'
2
+ require 'perl/interpreter'
3
+
4
+ module Perl
5
+ class Rack
6
+ def initialize(filename)
7
+ @interpreter = Perl::Interpreter.new
8
+ @app = @interpreter.load(filename)
9
+ end
10
+
11
+ def call(env)
12
+ @interpreter.call(@app, {:ref => clean_env(env)}, :scalar) do |ret|
13
+ value = ret.deref.value # Array
14
+
15
+ status = value[0].value
16
+
17
+ v1 = value[1].deref.value
18
+ headers = Hash[*v1.map { |v| v.value }]
19
+
20
+ body = value[2].deref.value.map { |v| v.value }
21
+
22
+ [status, headers, body]
23
+ end
24
+ rescue => e
25
+ puts "e: #{e.inspect}\n#{e.backtrace.join("\n")}"
26
+ end
27
+
28
+ def clean_env(hash)
29
+ ret = hash.dup
30
+ if defined?(PhusionPassenger)
31
+ ret = ret.reject do |k,v|
32
+ v.is_a?(PhusionPassenger::Utils::RewindableInput)
33
+ end
34
+ end
35
+ ret.tap do |h|
36
+ ["async.close"].each do |k|
37
+ if h.has_key?(k)
38
+ puts "Cannot handle env['#{k}'] (#{k} => #{h[k].inspect}), skipping"
39
+ h.delete("async.close")
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
data/lib/perl/shell.rb ADDED
@@ -0,0 +1,28 @@
1
+ require 'perl'
2
+ require 'perl/common'
3
+
4
+ module Perl
5
+ class Shell
6
+ include Perl::Common
7
+
8
+ class << self
9
+ def run
10
+ new.run
11
+ end
12
+ end
13
+
14
+ def initialize
15
+ Perl.setup
16
+
17
+ @my_perl = Perl.perl_alloc
18
+ Perl.perl_construct(@my_perl)
19
+ end
20
+
21
+ def run
22
+ argc, argv = argv_to_ffi
23
+
24
+ Perl.perl_parse(@my_perl, nil, argc, argv, nil)
25
+ Perl.perl_run(@my_perl)
26
+ end
27
+ end
28
+ end
data/lib/perl/stack.rb ADDED
@@ -0,0 +1,99 @@
1
+ module Perl; class Stack; end; end
2
+
3
+ require 'perl/stack/function'
4
+
5
+ module Perl
6
+ class Stack
7
+ class << self
8
+ def function_stack(args, &block)
9
+ Function.new(self.new, args, &block)
10
+ end
11
+ end
12
+
13
+ def initialize
14
+ @sp = nil
15
+ end
16
+
17
+ def dSP
18
+ @sp = Perl.curinterp[:Istack_sp].tap { |sp| trace("dSP: @sp=#{sp}") }
19
+ end
20
+ alias_method :spagain, :dSP
21
+
22
+ def enter
23
+ Perl.Perl_push_scope(Perl.PL_curinterp)
24
+ end
25
+
26
+ def savetmps
27
+ curinterp = Perl.curinterp
28
+ trace("savetmps: curinterp=#{curinterp.to_ptr.inspect}")
29
+
30
+ trace("savetmps: tmps_floor=#{curinterp[:Itmps_floor].inspect}")
31
+ addr = Perl.PL_curinterp + curinterp.offset_of(:Itmps_floor)
32
+ trace("addr=#{addr.inspect}")
33
+
34
+ Perl.Perl_save_int(Perl.PL_curinterp, addr)
35
+ trace("savetmps: tmps_floor now #{curinterp[:Itmps_floor].inspect}")
36
+
37
+ trace("curinterp[:Itmps_ix] was #{curinterp[:Itmps_ix].inspect}")
38
+ curinterp[:Itmps_floor] = curinterp[:Itmps_ix]
39
+ trace("savetmps: tmps_floor now #{curinterp[:Itmps_floor].inspect}")
40
+ end
41
+
42
+ def pushmark
43
+ trace("pushmark: @sp=#{@sp}")
44
+
45
+ curinterp = Perl.curinterp
46
+ trace("curinterp[:Imarkstack_ptr] was #{curinterp[:Imarkstack_ptr].inspect} == #{curinterp[:Imarkstack_max].inspect}")
47
+ curinterp[:Imarkstack_ptr] += FFI.type_size(:int32)
48
+ trace("curinterp[:Imarkstack_ptr] now #{curinterp[:Imarkstack_ptr].inspect}")
49
+ if curinterp[:Imarkstack_ptr] == curinterp[:Imarkstack_max]
50
+ Perl.Perl_markstack_grow(Perl.PL_curinterp)
51
+ end
52
+ trace("curinterp[:Imarkstack_ptr] <= #{@sp.address - curinterp[:Istack_base].address}")
53
+ curinterp[:Imarkstack_ptr].put_pointer(0, @sp.address - curinterp[:Istack_base].address)
54
+ trace("curinterp[:Imarkstack_ptr] now #{curinterp[:Imarkstack_ptr].inspect}")
55
+ end
56
+
57
+ def push(sv)
58
+ trace("push: @sp=#{@sp}")
59
+ @sp += FFI.type_size(:pointer)
60
+ @sp.put_pointer(0, sv)
61
+ trace("push: is now @sp=#{@sp}")
62
+ end
63
+
64
+ def putback
65
+ trace("putback: @sp=#{@sp}")
66
+
67
+ curinterp = Perl.curinterp
68
+ curinterp[:Istack_sp] = @sp
69
+ end
70
+
71
+ def pops
72
+ trace("pops: @sp=#{@sp}")
73
+
74
+ ret = @sp.get_pointer(0)
75
+ @sp = FFI::Pointer.new(@sp.address - FFI.type_size(:pointer))
76
+ trace("pops: now @sp=#{@sp}")
77
+ ret
78
+ end
79
+
80
+ def freetmps
81
+ curinterp = Perl.curinterp
82
+ trace("#{curinterp[:Itmps_ix].inspect} > #{curinterp[:Itmps_floor].inspect}")
83
+
84
+ if curinterp[:Itmps_ix] > curinterp[:Itmps_floor]
85
+ Perl.Perl_free_tmps(Perl.PL_curinterp)
86
+ trace("#{curinterp[:Itmps_ix].inspect} > #{curinterp[:Itmps_floor].inspect}")
87
+ end
88
+ end
89
+
90
+ def leave
91
+ Perl.Perl_pop_scope(Perl.PL_curinterp)
92
+ end
93
+
94
+ protected
95
+ def trace(msg)
96
+ $stderr.puts(msg) if false
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,67 @@
1
+ class Perl::Stack::Function
2
+ def initialize(stack, args, &block)
3
+ @stack = stack
4
+ @stack.dSP
5
+ @stack.enter
6
+ @stack.savetmps
7
+
8
+ case args
9
+ when nil
10
+ # nothing
11
+ when Hash
12
+ init_with_hash(args)
13
+ else
14
+ init_with_array(Array(args))
15
+ end
16
+
17
+ yield(self)
18
+ ensure
19
+ if @stack
20
+ @stack.freetmps
21
+ @stack.leave
22
+ end
23
+ end
24
+
25
+ def push(value)
26
+ value = Perl.Perl_sv_2mortal(Perl.PL_curinterp, value)
27
+ @stack.push(value)
28
+ end
29
+
30
+ def pop_scalar
31
+ @stack.spagain
32
+ return @stack.pops
33
+ ensure
34
+ @stack.putback
35
+ end
36
+
37
+ protected
38
+ def init_with_hash(args)
39
+ return unless args.any?
40
+
41
+ begin
42
+ @stack.pushmark
43
+ args.each_pair do |type, arg|
44
+ value = arg.to_perl
45
+ value = Perl.Perl_newRV_noinc(Perl.PL_curinterp, value) if type == :ref
46
+ push(value)
47
+ end
48
+ ensure
49
+ @stack.putback
50
+ end
51
+ end
52
+
53
+ def init_with_array(args)
54
+ return unless args.any?
55
+
56
+ args = Array(args)
57
+ begin
58
+ @stack.pushmark
59
+ args.each do |arg|
60
+ value = arg.to_perl
61
+ push(value)
62
+ end
63
+ ensure
64
+ @stack.putback
65
+ end
66
+ end
67
+ end