furnace 0.0.1 → 0.0.2

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,116 @@
1
+ module Furnace::AST
2
+ class Matcher
3
+ SpecialAny = MatcherSpecial.new(:any)
4
+ SpecialSubset = MatcherSpecial.define(:subset)
5
+
6
+ def initialize(&block)
7
+ @pattern = self.class.class_exec(&block)
8
+ end
9
+
10
+ def match(object)
11
+ genmatch(object.to_astlet, @pattern)
12
+ end
13
+
14
+ def find_one(collection)
15
+ collection.find do |elem|
16
+ result = match elem
17
+ yield elem, result if block_given? && result
18
+ result
19
+ end
20
+ end
21
+
22
+ def find_all(collection)
23
+ collection.select do |elem|
24
+ result = match elem
25
+ yield elem, result if block_given? && result
26
+ result
27
+ end
28
+ end
29
+
30
+ class << self
31
+ def any
32
+ SpecialAny
33
+ end
34
+
35
+ def subset
36
+ SpecialSubset
37
+ end
38
+
39
+ def capture(name)
40
+ MatcherSpecial.new(:capture, name)
41
+ end
42
+ end
43
+
44
+ protected
45
+
46
+ def submatch(array, pattern)
47
+ matches = true
48
+
49
+ pattern.each_with_index do |subpattern, index|
50
+ if array[index].nil?
51
+ return false
52
+ end
53
+
54
+ case subpattern
55
+ when SpecialAny
56
+ # it matches
57
+ when MatcherSpecial
58
+ if subpattern.type == :subset
59
+ all_submatches = true
60
+
61
+ subpattern.params.each do |pattern_case|
62
+ submatches = false
63
+ array[index..-1].each do |subset_elem|
64
+ submatches ||= genmatch(subset_elem, pattern_case)
65
+ break if submatches
66
+ end
67
+
68
+ all_submatches &&= submatches
69
+ break unless all_submatches
70
+ end
71
+
72
+ matches &&= all_submatches
73
+ end
74
+ when Array
75
+ matches &&= genmatch(array[index], subpattern)
76
+ else
77
+ matches &&= array[index] == subpattern
78
+ end
79
+
80
+ break unless matches
81
+ end
82
+
83
+ matches
84
+ end
85
+
86
+ def genmatch(astlet, pattern)
87
+ # if astlet.respond_to? :to_sexp
88
+ # puts "match #{astlet.to_sexp} of #{pattern}"
89
+ # else
90
+ # puts "match #{astlet} of #{pattern}"
91
+ # end
92
+
93
+ if pattern.first.is_a?(Symbol)
94
+ # Match an astlet
95
+ type, *rest = pattern
96
+
97
+ if astlet.is_a? Node
98
+ if astlet.type == type
99
+ submatch(astlet.children, rest)
100
+ else
101
+ false
102
+ end
103
+ else
104
+ false
105
+ end
106
+ else
107
+ # Match an array
108
+ if astlet.is_a? Array
109
+ submatch(astlet, pattern)
110
+ else
111
+ false
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,13 @@
1
+ module Furnace::AST
2
+ class MatcherSpecial
3
+ attr_reader :type, :params
4
+
5
+ def initialize(type, params=nil)
6
+ @type, @params = type, params
7
+ end
8
+
9
+ def self.define(type)
10
+ lambda { |*args| new(type, args) }
11
+ end
12
+ end
13
+ end
@@ -1,70 +1,96 @@
1
- module Furnace
2
- module AST
3
- class Node
4
- attr_accessor :type, :parent, :children, :metadata
1
+ module Furnace::AST
2
+ class Node
3
+ attr_accessor :type, :parent, :children, :metadata
5
4
 
6
- def initialize(type, children=[], metadata={})
7
- @type, @children, @metadata = type.to_sym, children, metadata
8
- end
9
-
10
- def update(type, children=nil, metadata={})
11
- @type = type
12
- @children = children || @children
5
+ def initialize(type, children=[], metadata={})
6
+ @type, @children, @metadata = type.to_sym, children, metadata
7
+ end
13
8
 
14
- # If something non-nil is passed, including default value, then merge.
15
- # Else, clear metadata store.
16
- if metadata
17
- @metadata.merge!(metadata)
18
- else
19
- @metadata = {}
9
+ def normalize_hierarchy!
10
+ @children.each do |child|
11
+ if child.respond_to? :parent=
12
+ child.parent = self
20
13
  end
21
14
 
22
- self
15
+ if child.respond_to? :normalize_hierarchy!
16
+ child.normalize_hierarchy!
17
+ end
23
18
  end
24
19
 
25
- def index
26
- parent.children.find_index(self)
27
- end
20
+ self
21
+ end
28
22
 
29
- def next
30
- parent.children[index + 1]
31
- end
23
+ def update(type, children=nil, metadata={})
24
+ @type = type
25
+ @children = children || @children
32
26
 
33
- def prev
34
- parent.children[index - 1]
27
+ # If something non-nil is passed, including default value, then merge.
28
+ # Else, clear metadata store.
29
+ if metadata
30
+ @metadata.merge!(metadata)
31
+ else
32
+ @metadata = {}
35
33
  end
36
34
 
37
- def to_s
38
- "(#{fancy_type} ...)"
39
- end
35
+ self
36
+ end
40
37
 
41
- def to_sexp(indent=0)
42
- str = "#{" " * indent}(#{fancy_type}"
38
+ def dup
39
+ node = super
40
+ node.children = @children.dup
41
+ node.metadata = @metadata.dup
42
+ node
43
+ end
43
44
 
44
- children.each do |child|
45
- if child.is_a? Node
46
- str << "\n#{child.to_sexp(indent + 1)}"
47
- else
48
- str << " #{child.inspect}"
49
- end
50
- end
45
+ def index
46
+ parent.children.find_index(self)
47
+ end
51
48
 
52
- str << ")"
49
+ def next
50
+ parent.children[index + 1]
51
+ end
53
52
 
54
- str
55
- end
56
- alias :inspect :to_sexp
53
+ def prev
54
+ parent.children[index - 1]
55
+ end
57
56
 
58
- protected
57
+ def to_s
58
+ "(#{fancy_type} ...)"
59
+ end
59
60
 
60
- def fancy_type
61
- dasherized = @type.to_s.gsub('_', '-')
62
- if @metadata[:label]
63
- "#{@metadata[:label]}:#{dasherized}"
61
+ def to_sexp(indent=0)
62
+ str = "#{" " * indent}(#{fancy_type}"
63
+
64
+ children.each do |child|
65
+ if (!children[0].is_a?(Node) && child.is_a?(Node)) ||
66
+ (children[0].is_a?(Node) && child.is_a?(Node) &&
67
+ child.children.any? { |c| c.is_a?(Node) || c.is_a?(Array) }) ||
68
+ (child.is_a?(Node) && child.metadata[:label])
69
+ str << "\n#{child.to_sexp(indent + 1)}"
64
70
  else
65
- dasherized
71
+ str << " #{child.inspect}"
66
72
  end
67
73
  end
74
+
75
+ str << ")"
76
+
77
+ str
78
+ end
79
+ alias :inspect :to_sexp
80
+
81
+ def to_astlet
82
+ self
83
+ end
84
+
85
+ protected
86
+
87
+ def fancy_type
88
+ dasherized = @type.to_s.gsub('_', '-')
89
+ if @metadata[:label]
90
+ "#{@metadata[:label]}:#{dasherized}"
91
+ else
92
+ dasherized
93
+ end
68
94
  end
69
95
  end
70
96
  end
@@ -1,36 +1,34 @@
1
- module Furnace
2
- module AST
3
- class SymbolicNode
4
- def initialize(name)
5
- @name = name.to_sym
6
- end
7
-
8
- def to_sym
9
- @name
10
- end
1
+ module Furnace::AST
2
+ class SymbolicNode
3
+ def initialize(name)
4
+ @name = name.to_sym
5
+ end
11
6
 
12
- def ===(name)
13
- @name == name.to_sym
14
- end
7
+ def to_sym
8
+ @name
9
+ end
15
10
 
16
- def inspect
17
- @name.to_s
18
- end
11
+ def ===(name)
12
+ @name == name.to_sym
19
13
  end
20
14
 
21
- class MethodName < SymbolicNode
22
- def inspect
23
- ".#{@name}"
24
- end
15
+ def inspect
16
+ @name.to_s
25
17
  end
18
+ end
26
19
 
27
- class LocalVariable < SymbolicNode
28
- def inspect
29
- "%#{@name}"
30
- end
20
+ class MethodName < SymbolicNode
21
+ def inspect
22
+ ".#{@name}"
31
23
  end
24
+ end
32
25
 
33
- class Constant < SymbolicNode
26
+ class LocalVariable < SymbolicNode
27
+ def inspect
28
+ "%#{@name}"
34
29
  end
35
30
  end
31
+
32
+ class Constant < SymbolicNode
33
+ end
36
34
  end
@@ -1,42 +1,40 @@
1
- module Furnace
2
- module AST
3
- module Visitor
4
- def visit(node)
5
- node.children.map! do |child|
6
- if child.is_a? Node
7
- visit child
8
-
9
- if child.type == :expand
10
- child = child.children
11
- end
1
+ module Furnace::AST
2
+ module Visitor
3
+ def visit(node)
4
+ node.children.map! do |child|
5
+ if child.is_a? Node
6
+ visit child
7
+
8
+ if child.type == :expand
9
+ child = child.children
12
10
  end
13
-
14
- child
15
11
  end
16
12
 
17
- node.children.flatten!
13
+ child
14
+ end
18
15
 
19
- node.children.delete_if do |child|
20
- if child.is_a? Node
21
- child.parent = node
16
+ node.children.flatten!
22
17
 
23
- child.type == :remove
24
- end
25
- end
18
+ node.children.delete_if do |child|
19
+ if child.is_a? Node
20
+ child.parent = node
26
21
 
27
- # Invoke a specific handler
28
- on_handler = :"on_#{node.type}"
29
- if respond_to? on_handler
30
- send on_handler, node
22
+ child.type == :remove
31
23
  end
24
+ end
32
25
 
33
- # Invoke a generic handler
34
- if respond_to? :on_any
35
- send :on_any, node
36
- end
26
+ # Invoke a specific handler
27
+ on_handler = :"on_#{node.type}"
28
+ if respond_to? on_handler
29
+ send on_handler, node
30
+ end
37
31
 
38
- node
32
+ # Invoke a generic handler
33
+ if respond_to? :on_any
34
+ send :on_any, node
39
35
  end
36
+
37
+ node
40
38
  end
41
39
  end
42
40
  end
@@ -0,0 +1,6 @@
1
+ require "furnace/ast/node"
2
+ require "furnace/ast/symbolic_node"
3
+ require "furnace/ast/visitor"
4
+
5
+ require "furnace/ast/matcher_special"
6
+ require "furnace/ast/matcher"
@@ -1,36 +1,34 @@
1
- module Furnace
2
- module CFG
3
- class Edge
4
- attr_accessor :source_operation, :source_label, :target_label
1
+ module Furnace::CFG
2
+ class Edge
3
+ attr_accessor :source_operation, :source_label, :target_label
5
4
 
6
- def initialize(cfg, source_operation, source_label, target_label)
7
- @cfg, @source_operation, @source_label, @target_label =
8
- cfg, source_operation, source_label, target_label
9
- end
5
+ def initialize(cfg, source_operation, source_label, target_label)
6
+ @cfg, @source_operation, @source_label, @target_label =
7
+ cfg, source_operation, source_label, target_label
8
+ end
10
9
 
11
- def source
12
- @cfg.find_node(@source_label)
13
- end
10
+ def source
11
+ @cfg.find_node(@source_label)
12
+ end
14
13
 
15
- def target
16
- @cfg.find_node(@target_label) if @target_label
17
- end
14
+ def target
15
+ @cfg.find_node(@target_label) if @target_label
16
+ end
18
17
 
19
- def source=(node)
20
- @source_label = node.label
21
- end
18
+ def source=(node)
19
+ @source_label = node.label
20
+ end
22
21
 
23
- def target=(node)
24
- if node
25
- @target_label = node.label
26
- else
27
- @target_label = nil
28
- end
22
+ def target=(node)
23
+ if node
24
+ @target_label = node.label
25
+ else
26
+ @target_label = nil
29
27
  end
28
+ end
30
29
 
31
- def inspect
32
- "<#{@source_label.inspect} -> #{@target_label.inspect}>"
33
- end
30
+ def inspect
31
+ "<#{@source_label.inspect} -> #{@target_label.inspect}>"
34
32
  end
35
33
  end
36
34
  end
@@ -1,57 +1,55 @@
1
- module Furnace
2
- module CFG
3
- class Graph
4
- attr_reader :nodes, :edges
1
+ module Furnace::CFG
2
+ class Graph
3
+ attr_reader :nodes, :edges
5
4
 
6
- def initialize
7
- @nodes = Set.new
8
- @edges = Set.new
5
+ def initialize
6
+ @nodes = Set.new
7
+ @edges = Set.new
9
8
 
10
- @pending_label = nil
11
- @pending_operations = []
12
- end
13
-
14
- def find_node(label)
15
- if node = @nodes.find { |n| n.label == label }
16
- node
17
- else
18
- raise "Cannot find CFG node #{label}"
19
- end
20
- end
9
+ @pending_label = nil
10
+ @pending_operations = []
11
+ end
21
12
 
22
- def expand(label, operation)
23
- @pending_label ||= label
24
- @pending_operations << operation
13
+ def find_node(label)
14
+ if node = @nodes.find { |n| n.label == label }
15
+ node
16
+ else
17
+ raise "Cannot find CFG node #{label}"
25
18
  end
19
+ end
26
20
 
27
- def transfer(targets)
28
- return unless @pending_label
21
+ def expand(label, operation)
22
+ @pending_label ||= label
23
+ @pending_operations << operation
24
+ end
29
25
 
30
- @nodes << CFG::Node.new(self, @pending_label, @pending_operations)
26
+ def transfer(targets)
27
+ return unless @pending_label
31
28
 
32
- targets.each do |operation, target|
33
- @edges << CFG::Edge.new(self, operation, @pending_label, target)
34
- end
29
+ @nodes << Node.new(self, @pending_label, @pending_operations)
35
30
 
36
- @pending_label = nil
37
- @pending_operations = []
31
+ targets.each do |operation, target|
32
+ @edges << Edge.new(self, operation, @pending_label, target)
38
33
  end
39
34
 
40
- def to_graphviz
41
- Graphviz.new do |graph|
42
- @nodes.each do |node|
43
- graph.node node.label, node.operations.map(&:inspect).join("\n")
44
- end
35
+ @pending_label = nil
36
+ @pending_operations = []
37
+ end
45
38
 
46
- @edges.each do |edge|
47
- if edge.source_operation.nil?
48
- label = "~"
49
- else
50
- label = edge.source_operation
51
- end
39
+ def to_graphviz
40
+ Furnace::Graphviz.new do |graph|
41
+ @nodes.each do |node|
42
+ graph.node node.label, node.operations.map(&:inspect).join("\n")
43
+ end
52
44
 
53
- graph.edge edge.source_label, edge.target_label, label
45
+ @edges.each do |edge|
46
+ if edge.source_operation.nil?
47
+ label = "~"
48
+ else
49
+ label = edge.source_operation
54
50
  end
51
+
52
+ graph.edge edge.source_label, edge.target_label, label
55
53
  end
56
54
  end
57
55
  end
@@ -1,38 +1,36 @@
1
- module Furnace
2
- module CFG
3
- class Node
4
- attr_reader :label, :operations
1
+ module Furnace::CFG
2
+ class Node
3
+ attr_reader :label, :operations
5
4
 
6
- def initialize(cfg, label, operations)
7
- @cfg, @label, @operations = cfg, label, operations
8
- end
5
+ def initialize(cfg, label, operations)
6
+ @cfg, @label, @operations = cfg, label, operations
7
+ end
9
8
 
10
- def entering_edges
11
- @cfg.edges.select { |e| e.target == self }
12
- end
9
+ def entering_edges
10
+ @cfg.edges.select { |e| e.target == self }
11
+ end
13
12
 
14
- def leaving_edges
15
- @cfg.edges.select { |e| e.source == self }
16
- end
13
+ def leaving_edges
14
+ @cfg.edges.select { |e| e.source == self }
15
+ end
17
16
 
18
- def leaving_edge(source)
19
- leaving_edges.find { |e| e.source_operation == source }
20
- end
17
+ def leaving_edge(source)
18
+ leaving_edges.find { |e| e.source_operation == source }
19
+ end
21
20
 
22
- def default_leaving_edge
23
- leaving_edge(nil)
24
- end
21
+ def default_leaving_edge
22
+ leaving_edge(nil)
23
+ end
25
24
 
26
- def ==(other)
27
- self.label == other.label
28
- end
25
+ def ==(other)
26
+ self.label == other.label
27
+ end
29
28
 
30
- def inspect
31
- if @label
32
- "<#{@label}:#{@operations.map(&:inspect).join ", "}>"
33
- else
34
- "<!exit>"
35
- end
29
+ def inspect
30
+ if @label
31
+ "<#{@label}:#{@operations.map(&:inspect).join ", "}>"
32
+ else
33
+ "<!exit>"
36
34
  end
37
35
  end
38
36
  end
@@ -0,0 +1,5 @@
1
+ require "set"
2
+
3
+ require "furnace/cfg/edge"
4
+ require "furnace/cfg/graph"
5
+ require "furnace/cfg/node"
@@ -1,7 +1,7 @@
1
1
  module Furnace
2
2
  module Transform
3
3
  class Pipeline
4
- def initialize(*stages)
4
+ def initialize(stages)
5
5
  @stages = stages
6
6
  end
7
7
 
@@ -0,0 +1,14 @@
1
+ module Furnace::Transform
2
+ end
3
+
4
+ require "furnace/transform/pipeline"
5
+
6
+ require "furnace/transform/rubinius/ast_build"
7
+ require "furnace/transform/rubinius/ast_normalize"
8
+
9
+ require "furnace/transform/generic/label_normalize"
10
+ require "furnace/transform/generic/cfg_build"
11
+ require "furnace/transform/generic/cfg_normalize"
12
+ require "furnace/transform/generic/anf_build"
13
+
14
+ require "furnace/transform/optimizing/fold_constants"
@@ -1,3 +1,3 @@
1
1
  module Furnace
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/lib/furnace.rb CHANGED
@@ -1,14 +1,7 @@
1
1
  require "furnace/version"
2
2
 
3
- require "set"
4
-
5
- require "furnace/ast/node"
6
- require "furnace/ast/symbolic_node"
7
- require "furnace/ast/visitor"
8
-
9
- require "furnace/cfg/node"
10
- require "furnace/cfg/edge"
11
- require "furnace/cfg/graph"
3
+ require "furnace/ast"
4
+ require "furnace/cfg"
12
5
 
13
6
  require "furnace/anf/node"
14
7
  require "furnace/anf/edge"
@@ -18,17 +11,7 @@ require "furnace/anf/if_node"
18
11
  require "furnace/anf/return_node"
19
12
  require "furnace/anf/graph"
20
13
 
21
- require "furnace/transform/pipeline"
22
-
23
- require "furnace/transform/rubinius/ast_build"
24
- require "furnace/transform/rubinius/ast_normalize"
25
-
26
- require "furnace/transform/generic/label_normalize"
27
- require "furnace/transform/generic/cfg_build"
28
- require "furnace/transform/generic/cfg_normalize"
29
- require "furnace/transform/generic/anf_build"
30
-
31
- require "furnace/transform/optimizing/fold_constants"
14
+ require "furnace/transform"
32
15
 
33
16
  require "furnace/graphviz"
34
17
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: furnace
3
3
  version: !ruby/object:Gem::Version
4
- hash: 880347952
4
+ hash: 988111682
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 1
10
- version: 0.0.1
9
+ - 2
10
+ version: 0.0.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Peter Zotov
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-01-13 00:00:00 Z
18
+ date: 2012-01-26 00:00:00 Z
19
19
  dependencies: []
20
20
 
21
21
  description: Furnace aims to compile Ruby code into small static executables by restricting its metaprogramming features.
@@ -42,13 +42,18 @@ files:
42
42
  - lib/furnace/anf/let_node.rb
43
43
  - lib/furnace/anf/node.rb
44
44
  - lib/furnace/anf/return_node.rb
45
+ - lib/furnace/ast.rb
46
+ - lib/furnace/ast/matcher.rb
47
+ - lib/furnace/ast/matcher_special.rb
45
48
  - lib/furnace/ast/node.rb
46
49
  - lib/furnace/ast/symbolic_node.rb
47
50
  - lib/furnace/ast/visitor.rb
51
+ - lib/furnace/cfg.rb
48
52
  - lib/furnace/cfg/edge.rb
49
53
  - lib/furnace/cfg/graph.rb
50
54
  - lib/furnace/cfg/node.rb
51
55
  - lib/furnace/graphviz.rb
56
+ - lib/furnace/transform.rb
52
57
  - lib/furnace/transform/generic/anf_build.rb
53
58
  - lib/furnace/transform/generic/cfg_build.rb
54
59
  - lib/furnace/transform/generic/cfg_normalize.rb