pure 0.1.0 → 0.2.0
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.
- data/CHANGES.rdoc +7 -0
- data/MANIFEST +44 -20
- data/README.rdoc +553 -16
- data/Rakefile +25 -2
- data/devel/jumpstart.rb +606 -253
- data/install.rb +1 -2
- data/lib/pure.rb +38 -16
- data/lib/pure/bundled_parsers.rb +4 -0
- data/lib/pure/bundled_plugin.rb +49 -0
- data/lib/pure/compiler/ruby_parser.rb +63 -0
- data/lib/pure/delegate.rb +16 -0
- data/lib/pure/driver.rb +33 -0
- data/lib/pure/dsl.rb +2 -0
- data/lib/pure/dsl_definition.rb +11 -0
- data/lib/pure/error.rb +89 -0
- data/lib/pure/extracted_functions.rb +11 -0
- data/lib/pure/extractor.rb +59 -0
- data/lib/pure/names.rb +9 -0
- data/lib/pure/native_worker.rb +27 -0
- data/lib/pure/parser/impl/base_parser.rb +21 -0
- data/lib/pure/parser/impl/internal.rb +31 -0
- data/lib/pure/parser/impl/ripper.rb +96 -0
- data/lib/pure/parser/impl/ruby_parser.rb +77 -0
- data/lib/pure/parser/internal.rb +4 -0
- data/lib/pure/parser/ripper.rb +2 -0
- data/lib/pure/parser/ruby_parser.rb +2 -0
- data/lib/pure/pure.rb +32 -0
- data/lib/pure/pure_module.rb +141 -0
- data/lib/pure/util.rb +15 -0
- data/lib/pure/version.rb +4 -0
- data/spec/compiler_ruby_parser_spec.rb +79 -0
- data/spec/compute_overrides_spec.rb +99 -0
- data/spec/compute_spec.rb +86 -0
- data/spec/compute_thread_spec.rb +29 -0
- data/spec/compute_timed_spec.rb +40 -0
- data/spec/delegate_spec.rb +141 -0
- data/spec/fstat_example.rb +26 -0
- data/spec/parser_sexp_spec.rb +100 -0
- data/spec/parser_spec.rb +18 -31
- data/spec/pure_combine_spec.rb +77 -0
- data/spec/pure_def_spec.rb +186 -0
- data/spec/pure_define_method_spec.rb +24 -0
- data/spec/pure_eval_spec.rb +18 -0
- data/spec/pure_fun_spec.rb +243 -0
- data/spec/pure_nested_spec.rb +35 -0
- data/spec/pure_parser_spec.rb +50 -0
- data/spec/pure_spec.rb +81 -0
- data/spec/pure_spec_base.rb +106 -0
- data/spec/pure_splat_spec.rb +18 -0
- data/spec/pure_two_defs_spec.rb +20 -0
- data/spec/pure_worker_spec.rb +33 -0
- data/spec/readme_spec.rb +36 -32
- data/spec/splat_spec.rb +12 -11
- data/spec/worker_spec.rb +89 -0
- metadata +157 -41
- data/devel/jumpstart/lazy_attribute.rb +0 -38
- data/devel/jumpstart/ruby.rb +0 -44
- data/devel/jumpstart/simple_installer.rb +0 -85
- data/lib/pure/pure_private/creator.rb +0 -27
- data/lib/pure/pure_private/driver.rb +0 -48
- data/lib/pure/pure_private/error.rb +0 -32
- data/lib/pure/pure_private/extractor.rb +0 -79
- data/lib/pure/pure_private/extractor_ripper.rb +0 -95
- data/lib/pure/pure_private/extractor_ruby_parser.rb +0 -47
- data/lib/pure/pure_private/function_database.rb +0 -10
- data/lib/pure/pure_private/singleton_features.rb +0 -67
- data/lib/pure/pure_private/util.rb +0 -23
- data/spec/basic_spec.rb +0 -38
- data/spec/combine_spec.rb +0 -62
- data/spec/common.rb +0 -44
- data/spec/error_spec.rb +0 -146
- data/spec/fun_spec.rb +0 -122
- data/spec/lazy_spec.rb +0 -22
- data/spec/subseqent_spec.rb +0 -42
- data/spec/timed_spec.rb +0 -30
@@ -1,27 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'pure/pure_private/util'
|
3
|
-
require 'pure/pure_private/singleton_features'
|
4
|
-
|
5
|
-
module Pure
|
6
|
-
module PurePrivate
|
7
|
-
module Creator
|
8
|
-
class << self
|
9
|
-
include Util
|
10
|
-
|
11
|
-
def create_module(&block)
|
12
|
-
mod = Module.new
|
13
|
-
fun_mod = Module.new
|
14
|
-
singleton_class_of(mod).module_eval {
|
15
|
-
include SingletonFeatures
|
16
|
-
@fun_mod = fun_mod
|
17
|
-
}
|
18
|
-
mod.module_eval(&block)
|
19
|
-
mod.module_eval {
|
20
|
-
include fun_mod
|
21
|
-
}
|
22
|
-
mod
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,48 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'pure/pure_private/function_database'
|
3
|
-
require 'pure/pure_private/error'
|
4
|
-
require 'comp_tree'
|
5
|
-
|
6
|
-
module Pure
|
7
|
-
module PurePrivate
|
8
|
-
module Driver
|
9
|
-
include FunctionDatabase
|
10
|
-
|
11
|
-
module_function
|
12
|
-
|
13
|
-
def build_and_compute(mod, root, num_threads, &block)
|
14
|
-
begin
|
15
|
-
CompTree.build do |driver|
|
16
|
-
mod.ancestors.each { |ancestor|
|
17
|
-
if defs = FUNCTION_DATABASE[ancestor]
|
18
|
-
defs.each_pair { |function_name, spec|
|
19
|
-
existing_node = driver.nodes[function_name]
|
20
|
-
if existing_node.nil? or existing_node.function.nil?
|
21
|
-
final_spec = spec.merge(:module => ancestor)
|
22
|
-
node = driver.define(function_name, *spec[:args])
|
23
|
-
node.function = yield function_name, final_spec
|
24
|
-
end
|
25
|
-
}
|
26
|
-
end
|
27
|
-
}
|
28
|
-
driver.compute(root, num_threads)
|
29
|
-
end
|
30
|
-
rescue CompTree::NoFunctionError => exception
|
31
|
-
raise PurePrivate::NoFunctionError, exception.message
|
32
|
-
rescue CompTree::ArgumentError => exception
|
33
|
-
raise PurePrivate::ArgumentError, exception.message
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def create_instance_and_compute(mod, root, opts)
|
38
|
-
num_threads = (opts.is_a?(Hash) ? opts[:threads] : opts).to_i
|
39
|
-
instance = Object.new.extend(mod)
|
40
|
-
build_and_compute(mod, root, num_threads) { |function_name, spec|
|
41
|
-
lambda { |*args|
|
42
|
-
instance.send(function_name, *args)
|
43
|
-
}
|
44
|
-
}
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
|
2
|
-
module Pure
|
3
|
-
module PurePrivate
|
4
|
-
class Error < StandardError
|
5
|
-
end
|
6
|
-
|
7
|
-
class NoFunctionError < Error
|
8
|
-
end
|
9
|
-
|
10
|
-
class ParseError < Error
|
11
|
-
end
|
12
|
-
|
13
|
-
class ArgumentError < Error
|
14
|
-
end
|
15
|
-
|
16
|
-
class SplatError < ParseError
|
17
|
-
def initialize(file, line)
|
18
|
-
super()
|
19
|
-
@file = file
|
20
|
-
@line = line
|
21
|
-
end
|
22
|
-
|
23
|
-
def message
|
24
|
-
"cannot use splat (*) argument in a pure function defined with `def' " +
|
25
|
-
"at #{@file}:#{@line}"
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
class NotImplementedError < Error
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
@@ -1,79 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'pure/pure_private/error'
|
3
|
-
require 'pure/pure_private/util'
|
4
|
-
|
5
|
-
module Pure
|
6
|
-
module PurePrivate
|
7
|
-
module Extractor
|
8
|
-
HAS_METHOD_PARAMETERS = Method.instance_methods.include?(:parameters)
|
9
|
-
|
10
|
-
DEFAULT_PARSER = (
|
11
|
-
if HAS_METHOD_PARAMETERS
|
12
|
-
nil
|
13
|
-
elsif RUBY_VERSION >= "1.9"
|
14
|
-
"ripper"
|
15
|
-
else
|
16
|
-
"ruby_parser"
|
17
|
-
end
|
18
|
-
)
|
19
|
-
|
20
|
-
@parser = nil
|
21
|
-
@engine = nil
|
22
|
-
@cache = Hash.new { |hash, key| hash[key] = Hash.new }
|
23
|
-
|
24
|
-
class << self
|
25
|
-
include Util
|
26
|
-
|
27
|
-
def extract(mod, method_name, backtrace)
|
28
|
-
file, line = file_line(backtrace.first)
|
29
|
-
if @parser.nil? and HAS_METHOD_PARAMETERS
|
30
|
-
if method_name == :fun
|
31
|
-
Hash.new
|
32
|
-
else
|
33
|
-
{
|
34
|
-
:name => method_name,
|
35
|
-
:args => mod.instance_method(method_name).parameters.map {
|
36
|
-
|type, name|
|
37
|
-
raise SplatError.new(file, line) if type == :rest
|
38
|
-
name
|
39
|
-
},
|
40
|
-
}
|
41
|
-
end
|
42
|
-
else
|
43
|
-
if @parser.nil?
|
44
|
-
self.parser = DEFAULT_PARSER
|
45
|
-
end
|
46
|
-
defs = @cache[@parser][file] || (
|
47
|
-
@cache[@parser][file] = @engine.new(file).run
|
48
|
-
)
|
49
|
-
spec = defs[line]
|
50
|
-
unless spec and spec[:name] and spec[:name] == method_name
|
51
|
-
raise PurePrivate::ParseError,
|
52
|
-
"failure parsing `#{method_name}' at #{file}:#{line}"
|
53
|
-
end
|
54
|
-
spec.merge(:file => file, :line => line)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def parser=(parser_name)
|
59
|
-
if parser_name.nil?
|
60
|
-
@engine = nil
|
61
|
-
else
|
62
|
-
require parser_name
|
63
|
-
begin
|
64
|
-
engine_name = "extractor_#{parser_name}"
|
65
|
-
require "pure/pure_private/#{engine_name}"
|
66
|
-
@engine = PurePrivate.const_get(to_camel_case(engine_name))
|
67
|
-
rescue LoadError
|
68
|
-
raise PurePrivate::NotImplementedError,
|
69
|
-
"parser not supported: #{parser_name}"
|
70
|
-
end
|
71
|
-
end
|
72
|
-
@parser = parser_name
|
73
|
-
end
|
74
|
-
|
75
|
-
attr_reader :parser
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
@@ -1,95 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'ripper'
|
3
|
-
|
4
|
-
module Pure
|
5
|
-
module PurePrivate
|
6
|
-
class ExtractorRipper
|
7
|
-
def initialize(file)
|
8
|
-
@file = file
|
9
|
-
@defs = Hash.new
|
10
|
-
end
|
11
|
-
|
12
|
-
def run
|
13
|
-
process(Ripper.sexp(File.read(@file)))
|
14
|
-
@defs
|
15
|
-
end
|
16
|
-
|
17
|
-
def process_def(sexp)
|
18
|
-
if sexp[0] == :def
|
19
|
-
name = sexp[1][1].to_sym
|
20
|
-
line = sexp[1][2][0]
|
21
|
-
params = (
|
22
|
-
case sexp[2].first
|
23
|
-
when :params
|
24
|
-
sexp[2]
|
25
|
-
when :paren
|
26
|
-
sexp[2][1]
|
27
|
-
else
|
28
|
-
raise PurePrivate::ParseError,
|
29
|
-
"unforeseen `def' syntax at #{@file}:#{line}"
|
30
|
-
end
|
31
|
-
)
|
32
|
-
if params.any? { |t| t and t[0] == :rest_param }
|
33
|
-
raise SplatError.new(@file, line)
|
34
|
-
end
|
35
|
-
args = (
|
36
|
-
if params[1].nil?
|
37
|
-
[]
|
38
|
-
else
|
39
|
-
params[1].map { |t| t[1].to_sym }
|
40
|
-
end
|
41
|
-
)
|
42
|
-
@defs[line] = {
|
43
|
-
:name => name,
|
44
|
-
:args => args,
|
45
|
-
:sexp => sexp,
|
46
|
-
}
|
47
|
-
true
|
48
|
-
else
|
49
|
-
false
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def process_fun(sexp)
|
54
|
-
if sexp[0] == :method_add_block and sexp[1].is_a?(Array)
|
55
|
-
line = (
|
56
|
-
if sexp[1][0] == :command and
|
57
|
-
sexp[1][1].is_a?(Array) and
|
58
|
-
sexp[1][1][1] == "fun"
|
59
|
-
sexp[1][1][2][0]
|
60
|
-
elsif sexp[1][0] == :method_add_arg and
|
61
|
-
sexp[1][1].is_a?(Array) and
|
62
|
-
sexp[1][1][0] == :fcall and
|
63
|
-
sexp[1][1][1].is_a?(Array) and
|
64
|
-
sexp[1][1][1][1] == "fun"
|
65
|
-
sexp[1][1][1][2][0]
|
66
|
-
else
|
67
|
-
nil
|
68
|
-
end
|
69
|
-
)
|
70
|
-
if line
|
71
|
-
@defs[line] = {
|
72
|
-
:name => :fun,
|
73
|
-
:sexp => sexp[2],
|
74
|
-
}
|
75
|
-
true
|
76
|
-
else
|
77
|
-
false
|
78
|
-
end
|
79
|
-
else
|
80
|
-
false
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def process(sexp)
|
85
|
-
if sexp.is_a? Array
|
86
|
-
process_def(sexp) or process_fun(sexp) or (
|
87
|
-
sexp.each { |sub_sexp|
|
88
|
-
process(sub_sexp)
|
89
|
-
}
|
90
|
-
)
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
@@ -1,47 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'ruby_parser'
|
3
|
-
require 'sexp_processor'
|
4
|
-
|
5
|
-
module Pure
|
6
|
-
module PurePrivate
|
7
|
-
class ExtractorRubyParser < SexpProcessor
|
8
|
-
def initialize(file)
|
9
|
-
super()
|
10
|
-
@file = file
|
11
|
-
@defs = Hash.new
|
12
|
-
end
|
13
|
-
|
14
|
-
def run
|
15
|
-
process(RubyParser.new.parse(File.read(@file)))
|
16
|
-
@defs
|
17
|
-
end
|
18
|
-
|
19
|
-
def process(sexp)
|
20
|
-
if sexp[0] == :defn
|
21
|
-
name = sexp[1]
|
22
|
-
args = sexp[2].to_a[1..-1]
|
23
|
-
if args.any? { |arg| arg.to_s =~ %r!\A\*! }
|
24
|
-
raise SplatError.new(@file, sexp.line)
|
25
|
-
end
|
26
|
-
@defs[sexp.line] = {
|
27
|
-
:name => name,
|
28
|
-
:args => args,
|
29
|
-
:sexp => sexp.dup,
|
30
|
-
}
|
31
|
-
sexp.clear
|
32
|
-
elsif sexp[0] == :iter and
|
33
|
-
sexp[1][0] == :call and
|
34
|
-
sexp[1][1] == nil and
|
35
|
-
sexp[1][2] == :fun
|
36
|
-
@defs[sexp[1].line] = {
|
37
|
-
:name => :fun,
|
38
|
-
:sexp => [sexp[2], sexp[3]],
|
39
|
-
}
|
40
|
-
sexp.clear
|
41
|
-
else
|
42
|
-
super
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
@@ -1,67 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'pure/pure_private/extractor'
|
3
|
-
require 'pure/pure_private/function_database'
|
4
|
-
require 'pure/pure_private/driver'
|
5
|
-
require 'pure/pure_private/error'
|
6
|
-
|
7
|
-
module Pure
|
8
|
-
module PurePrivate
|
9
|
-
module SingletonFeatures
|
10
|
-
include FunctionDatabase
|
11
|
-
|
12
|
-
def compute(root, opts)
|
13
|
-
Driver.create_instance_and_compute(self, root, opts)
|
14
|
-
end
|
15
|
-
|
16
|
-
def fun(*args, &block)
|
17
|
-
fun_mod = class << self ; @fun_mod ; end
|
18
|
-
node_name, child_names = (
|
19
|
-
if args.size == 1
|
20
|
-
arg = args.first
|
21
|
-
if arg.is_a? Hash
|
22
|
-
unless arg.size == 1
|
23
|
-
raise PurePrivate::ArgumentError,
|
24
|
-
"`fun' given hash of size != 1"
|
25
|
-
end
|
26
|
-
arg.to_a.first
|
27
|
-
else
|
28
|
-
[arg, []]
|
29
|
-
end
|
30
|
-
else
|
31
|
-
raise PurePrivate::ArgumentError,
|
32
|
-
"wrong number of arguments (\#{args.size} for 1)"
|
33
|
-
end
|
34
|
-
)
|
35
|
-
child_syms = (
|
36
|
-
if child_names.is_a? Enumerable
|
37
|
-
child_names.map { |t| t.to_sym }
|
38
|
-
else
|
39
|
-
[child_names.to_sym]
|
40
|
-
end
|
41
|
-
)
|
42
|
-
node_sym = node_name.to_sym
|
43
|
-
fun_mod.module_eval {
|
44
|
-
define_method(node_sym, &block)
|
45
|
-
}
|
46
|
-
spec = Extractor.extract(fun_mod, :fun, caller)
|
47
|
-
FUNCTION_DATABASE[fun_mod][node_sym] = spec.merge(
|
48
|
-
:name => node_sym,
|
49
|
-
:args => child_syms,
|
50
|
-
:origin => :fun
|
51
|
-
)
|
52
|
-
nil
|
53
|
-
end
|
54
|
-
|
55
|
-
def method_added(function_name)
|
56
|
-
FUNCTION_DATABASE[self][function_name] = (
|
57
|
-
Extractor.extract(self, function_name, caller).merge(:origin => :def)
|
58
|
-
)
|
59
|
-
end
|
60
|
-
|
61
|
-
def define_method(*args, &block)
|
62
|
-
raise PurePrivate::NotImplementedError,
|
63
|
-
"define_method called (use the `fun' method instead)"
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
|
2
|
-
module Pure
|
3
|
-
module PurePrivate
|
4
|
-
module Util
|
5
|
-
module_function
|
6
|
-
|
7
|
-
def file_line(backtrace)
|
8
|
-
file, line = backtrace.match(%r!\A(.*?):(\d+)!).captures
|
9
|
-
return file, line.to_i
|
10
|
-
end
|
11
|
-
|
12
|
-
def singleton_class_of(obj)
|
13
|
-
class << obj
|
14
|
-
self
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def to_camel_case(str)
|
19
|
-
str.split('_').map { |t| t.capitalize }.join
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
data/spec/basic_spec.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + "/common"
|
2
|
-
|
3
|
-
describe "basic computation" do
|
4
|
-
before :all do
|
5
|
-
@mod = pure do
|
6
|
-
def area(width, height)
|
7
|
-
width*height
|
8
|
-
end
|
9
|
-
|
10
|
-
def width(border)
|
11
|
-
20 + border
|
12
|
-
end
|
13
|
-
|
14
|
-
def height(border)
|
15
|
-
30 + border
|
16
|
-
end
|
17
|
-
|
18
|
-
def border
|
19
|
-
5
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
max_threads = 50
|
25
|
-
|
26
|
-
it "should run using compute(:x, :threads => n) syntax" do
|
27
|
-
(1..max_threads).each { |n|
|
28
|
-
@mod.compute(:area, :threads => n).should == (20 + 5)*(30 + 5)
|
29
|
-
}
|
30
|
-
end
|
31
|
-
|
32
|
-
it "should run using compute(:x, n) syntax" do
|
33
|
-
(1..max_threads).each { |n|
|
34
|
-
@mod.compute(:area, n).should == (20 + 5)*(30 + 5)
|
35
|
-
}
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|