ruby-perl 0.99.15j

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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