morpher 0.2.6
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of morpher might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/.circle.yml +6 -0
- data/.gitignore +5 -0
- data/.rspec +4 -0
- data/.rubocop.yml +8 -0
- data/Changelog.md +60 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.md +56 -0
- data/Rakefile +95 -0
- data/circle.yml +7 -0
- data/config/devtools.yml +2 -0
- data/config/flay.yml +3 -0
- data/config/flog.yml +2 -0
- data/config/heckle.yml +3 -0
- data/config/mutant.yml +8 -0
- data/config/reek.yml +109 -0
- data/config/rubocop.yml +138 -0
- data/config/yardstick.yml +2 -0
- data/examples/README.md +13 -0
- data/examples/a.rb +25 -0
- data/examples/b.rb +35 -0
- data/lib/morpher.rb +111 -0
- data/lib/morpher/compiler.rb +17 -0
- data/lib/morpher/compiler/emitter.rb +82 -0
- data/lib/morpher/compiler/error.rb +84 -0
- data/lib/morpher/compiler/evaluator.rb +63 -0
- data/lib/morpher/compiler/evaluator/emitter.rb +224 -0
- data/lib/morpher/compiler/preprocessor.rb +29 -0
- data/lib/morpher/compiler/preprocessor/emitter.rb +54 -0
- data/lib/morpher/compiler/preprocessor/emitter/anima.rb +69 -0
- data/lib/morpher/compiler/preprocessor/emitter/boolean.rb +31 -0
- data/lib/morpher/compiler/preprocessor/emitter/key.rb +87 -0
- data/lib/morpher/compiler/preprocessor/emitter/noop.rb +45 -0
- data/lib/morpher/compiler/preprocessor/emitter/param.rb +50 -0
- data/lib/morpher/evaluation.rb +118 -0
- data/lib/morpher/evaluator.rb +40 -0
- data/lib/morpher/evaluator/binary.rb +46 -0
- data/lib/morpher/evaluator/nary.rb +97 -0
- data/lib/morpher/evaluator/nullary.rb +92 -0
- data/lib/morpher/evaluator/nullary/parameterized.rb +48 -0
- data/lib/morpher/evaluator/predicate.rb +22 -0
- data/lib/morpher/evaluator/predicate/boolean.rb +76 -0
- data/lib/morpher/evaluator/predicate/contradiction.rb +36 -0
- data/lib/morpher/evaluator/predicate/eql.rb +50 -0
- data/lib/morpher/evaluator/predicate/negation.rb +52 -0
- data/lib/morpher/evaluator/predicate/primitive.rb +49 -0
- data/lib/morpher/evaluator/predicate/tautology.rb +36 -0
- data/lib/morpher/evaluator/transformer.rb +75 -0
- data/lib/morpher/evaluator/transformer/attribute.rb +25 -0
- data/lib/morpher/evaluator/transformer/block.rb +81 -0
- data/lib/morpher/evaluator/transformer/coerce.rb +166 -0
- data/lib/morpher/evaluator/transformer/custom.rb +34 -0
- data/lib/morpher/evaluator/transformer/domain.rb +86 -0
- data/lib/morpher/evaluator/transformer/domain/attribute_accessors.rb +60 -0
- data/lib/morpher/evaluator/transformer/domain/attribute_hash.rb +52 -0
- data/lib/morpher/evaluator/transformer/domain/instance_variables.rb +60 -0
- data/lib/morpher/evaluator/transformer/domain/param.rb +54 -0
- data/lib/morpher/evaluator/transformer/guard.rb +62 -0
- data/lib/morpher/evaluator/transformer/hash_transform.rb +149 -0
- data/lib/morpher/evaluator/transformer/input.rb +37 -0
- data/lib/morpher/evaluator/transformer/key.rb +86 -0
- data/lib/morpher/evaluator/transformer/map.rb +100 -0
- data/lib/morpher/evaluator/transformer/merge.rb +25 -0
- data/lib/morpher/evaluator/transformer/static.rb +27 -0
- data/lib/morpher/evaluator/unary.rb +79 -0
- data/lib/morpher/node_helpers.rb +19 -0
- data/lib/morpher/printer.rb +233 -0
- data/lib/morpher/printer/mixin.rb +58 -0
- data/lib/morpher/registry.rb +51 -0
- data/lib/morpher/type_lookup.rb +51 -0
- data/morpher.gemspec +29 -0
- data/spec/integration_spec.rb +184 -0
- data/spec/rcov.opts +7 -0
- data/spec/shared/evaluator_behavior.rb +155 -0
- data/spec/spec_helper.rb +36 -0
- data/spec/support/ice_nine_config.rb +8 -0
- data/spec/support/let_mock_helper.rb +8 -0
- data/spec/support/strip_helper.rb +12 -0
- data/spec/unit/morpher/compiler/preprocessor_spec.rb +46 -0
- data/spec/unit/morpher/evaluator/nullary/parameterized_spec.rb +25 -0
- data/spec/unit/morpher/evaluator/predicate/boolean/and_spec.rb +11 -0
- data/spec/unit/morpher/evaluator/predicate/boolean/or_spec.rb +26 -0
- data/spec/unit/morpher/evaluator/predicate/boolean/xor_spec.rb +26 -0
- data/spec/unit/morpher/evaluator/predicate/contrandiction_spec.rb +7 -0
- data/spec/unit/morpher/evaluator/predicate/eql_spec.rb +11 -0
- data/spec/unit/morpher/evaluator/predicate/negation_spec.rb +10 -0
- data/spec/unit/morpher/evaluator/predicate/primitive_spec.rb +17 -0
- data/spec/unit/morpher/evaluator/predicate/tautology_spec.rb +7 -0
- data/spec/unit/morpher/evaluator/transformer/attribute_spec.rb +9 -0
- data/spec/unit/morpher/evaluator/transformer/block_spec.rb +92 -0
- data/spec/unit/morpher/evaluator/transformer/coerce/parse_int_spec.rb +23 -0
- data/spec/unit/morpher/evaluator/transformer/custom_spec.rb +13 -0
- data/spec/unit/morpher/evaluator/transformer/domain/attribute_accessors_spec.rb +48 -0
- data/spec/unit/morpher/evaluator/transformer/domain/attribute_hash_spec.rb +40 -0
- data/spec/unit/morpher/evaluator/transformer/domain/instance_variables_spec.rb +47 -0
- data/spec/unit/morpher/evaluator/transformer/guard_spec.rb +12 -0
- data/spec/unit/morpher/evaluator/transformer/hash_transform_spec.rb +47 -0
- data/spec/unit/morpher/evaluator/transformer/input_spec.rb +11 -0
- data/spec/unit/morpher/evaluator/transformer/map_spec.rb +25 -0
- data/spec/unit/morpher/evaluator/transformer/static_spec.rb +10 -0
- data/spec/unit/morpher/evaluator_spec.rb +15 -0
- data/spec/unit/morpher/printer_spec.rb +21 -0
- data/spec/unit/morpher/registry_spec.rb +11 -0
- data/spec/unit/morpher_spec.rb +53 -0
- metadata +302 -0
data/examples/README.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Morpher Examples
|
2
|
+
================
|
3
|
+
|
4
|
+
These are some random examples I captured on parings.
|
5
|
+
At this early stage the examples are very "unimpressive" and only scratch the surface.
|
6
|
+
|
7
|
+
The examples are used for parings to show API in action under IRB:
|
8
|
+
|
9
|
+
```
|
10
|
+
cd morpher
|
11
|
+
bundle exec irb -I lib -r ./examples/your_example.rb
|
12
|
+
# Now access the constants defined in example to play with the evaluators
|
13
|
+
```
|
data/examples/a.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'morpher'
|
2
|
+
|
3
|
+
extend Morpher::NodeHelpers
|
4
|
+
|
5
|
+
class Input
|
6
|
+
include Anima.new(:foo)
|
7
|
+
end # Input
|
8
|
+
|
9
|
+
node =
|
10
|
+
s(:block,
|
11
|
+
s(:guard, s(:primitive, Hash)),
|
12
|
+
s(:hash_transform,
|
13
|
+
s(:key_symbolize, :foo,
|
14
|
+
s(:guard,
|
15
|
+
s(:or,
|
16
|
+
s(:primitive, String),
|
17
|
+
s(:primitive, NilClass)
|
18
|
+
)
|
19
|
+
)
|
20
|
+
)
|
21
|
+
),
|
22
|
+
s(:load_attribute_hash, s(:param, Input))
|
23
|
+
)
|
24
|
+
|
25
|
+
EVALUATOR = Morpher.compile(node)
|
data/examples/b.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'morpher'
|
2
|
+
|
3
|
+
extend Morpher::NodeHelpers
|
4
|
+
|
5
|
+
class Address
|
6
|
+
include Anima.new(:street)
|
7
|
+
end
|
8
|
+
|
9
|
+
class Person
|
10
|
+
include Anima.new(:address)
|
11
|
+
end
|
12
|
+
|
13
|
+
node = s(:block,
|
14
|
+
s(:guard, s(:primitive, Hash)),
|
15
|
+
s(:hash_transform,
|
16
|
+
s(:key_symbolize, 'street',
|
17
|
+
s(:guard, s(:primitive, String))
|
18
|
+
)
|
19
|
+
),
|
20
|
+
s(:load_attribute_hash, s(:param, Address))
|
21
|
+
)
|
22
|
+
|
23
|
+
ADDRESS_EVALUATOR = Morpher.compile(node)
|
24
|
+
|
25
|
+
node = s(:block,
|
26
|
+
s(:guard, s(:primitive, Hash)),
|
27
|
+
s(:hash_transform,
|
28
|
+
s(:key_symbolize, 'address',
|
29
|
+
ADDRESS_EVALUATOR.node
|
30
|
+
)
|
31
|
+
),
|
32
|
+
s(:load_attribute_hash, s(:param, Person))
|
33
|
+
)
|
34
|
+
|
35
|
+
PERSON_EVALUATOR = Morpher.compile(node)
|
data/lib/morpher.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'abstract_type'
|
2
|
+
require 'concord'
|
3
|
+
require 'anima'
|
4
|
+
require 'ast'
|
5
|
+
require 'procto'
|
6
|
+
|
7
|
+
# Library namespace module
|
8
|
+
module Morpher
|
9
|
+
|
10
|
+
Undefined = Module.new.freeze
|
11
|
+
|
12
|
+
# Return evaluator from node
|
13
|
+
#
|
14
|
+
# @param [Node]
|
15
|
+
#
|
16
|
+
# @return [Evaluator]
|
17
|
+
#
|
18
|
+
# @api private
|
19
|
+
#
|
20
|
+
def self.compile(node)
|
21
|
+
node = Compiler::Preprocessor::DEFAULT.call(node)
|
22
|
+
Compiler::Evaluator::DEFAULT.call(node)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Return evaluate block to produce an AST node
|
26
|
+
#
|
27
|
+
# @return [AST::Node]
|
28
|
+
#
|
29
|
+
# @api private
|
30
|
+
#
|
31
|
+
def self.sexp(&block)
|
32
|
+
NodeHelpers.module_eval(&block)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Build morpher from yielding sexp blog
|
36
|
+
#
|
37
|
+
# @return [Evaluator]
|
38
|
+
#
|
39
|
+
# @api private
|
40
|
+
#
|
41
|
+
def self.build(&block)
|
42
|
+
compile(sexp(&block))
|
43
|
+
end
|
44
|
+
|
45
|
+
end # Morpher
|
46
|
+
|
47
|
+
require 'morpher/node_helpers'
|
48
|
+
require 'morpher/registry'
|
49
|
+
require 'morpher/printer'
|
50
|
+
require 'morpher/printer/mixin'
|
51
|
+
require 'morpher/evaluator'
|
52
|
+
require 'morpher/evaluator/nullary'
|
53
|
+
require 'morpher/evaluator/nullary/parameterized'
|
54
|
+
require 'morpher/evaluator/unary'
|
55
|
+
require 'morpher/evaluator/binary'
|
56
|
+
require 'morpher/evaluator/nary'
|
57
|
+
require 'morpher/evaluator/transformer'
|
58
|
+
require 'morpher/evaluator/transformer/block'
|
59
|
+
require 'morpher/evaluator/transformer/key'
|
60
|
+
require 'morpher/evaluator/transformer/guard'
|
61
|
+
require 'morpher/evaluator/transformer/attribute'
|
62
|
+
require 'morpher/evaluator/transformer/hash_transform'
|
63
|
+
require 'morpher/evaluator/transformer/map'
|
64
|
+
require 'morpher/evaluator/transformer/static'
|
65
|
+
require 'morpher/evaluator/transformer/input'
|
66
|
+
require 'morpher/evaluator/transformer/merge'
|
67
|
+
require 'morpher/evaluator/transformer/coerce'
|
68
|
+
require 'morpher/evaluator/transformer/custom'
|
69
|
+
require 'morpher/evaluator/transformer/domain'
|
70
|
+
require 'morpher/evaluator/transformer/domain/param'
|
71
|
+
require 'morpher/evaluator/transformer/domain/attribute_hash'
|
72
|
+
require 'morpher/evaluator/transformer/domain/instance_variables'
|
73
|
+
require 'morpher/evaluator/transformer/domain/attribute_accessors'
|
74
|
+
require 'morpher/evaluator/predicate'
|
75
|
+
require 'morpher/evaluator/predicate/eql'
|
76
|
+
require 'morpher/evaluator/predicate/primitive'
|
77
|
+
require 'morpher/evaluator/predicate/negation'
|
78
|
+
require 'morpher/evaluator/predicate/tautology'
|
79
|
+
require 'morpher/evaluator/predicate/contradiction'
|
80
|
+
require 'morpher/evaluator/predicate/boolean'
|
81
|
+
require 'morpher/evaluation'
|
82
|
+
require 'morpher/evaluation'
|
83
|
+
require 'morpher/type_lookup'
|
84
|
+
require 'morpher/compiler'
|
85
|
+
require 'morpher/compiler/error'
|
86
|
+
require 'morpher/compiler/emitter'
|
87
|
+
require 'morpher/compiler/evaluator'
|
88
|
+
require 'morpher/compiler/evaluator/emitter'
|
89
|
+
require 'morpher/compiler/preprocessor'
|
90
|
+
require 'morpher/compiler/preprocessor/emitter'
|
91
|
+
require 'morpher/compiler/preprocessor/emitter/noop'
|
92
|
+
require 'morpher/compiler/preprocessor/emitter/key'
|
93
|
+
require 'morpher/compiler/preprocessor/emitter/param'
|
94
|
+
require 'morpher/compiler/preprocessor/emitter/boolean'
|
95
|
+
require 'morpher/compiler/preprocessor/emitter/anima'
|
96
|
+
|
97
|
+
module Morpher
|
98
|
+
class Compiler
|
99
|
+
|
100
|
+
class Preprocessor
|
101
|
+
# Default preprocessor compiler
|
102
|
+
DEFAULT = new(Emitter::REGISTRY.freeze)
|
103
|
+
end # Preprocessor
|
104
|
+
|
105
|
+
class Evaluator
|
106
|
+
# Default evaluator compiler
|
107
|
+
DEFAULT = new(Morpher::Evaluator::REGISTRY, Emitter::REGISTRY.freeze)
|
108
|
+
end # Evaluator
|
109
|
+
|
110
|
+
end # Compiler
|
111
|
+
end # Morpher
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Morpher
|
2
|
+
# Abstract compiler base class
|
3
|
+
class Compiler
|
4
|
+
include AbstractType
|
5
|
+
|
6
|
+
# Call compiler
|
7
|
+
#
|
8
|
+
# @param [Node] node
|
9
|
+
#
|
10
|
+
# @return [Object]
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
#
|
14
|
+
abstract_method :call
|
15
|
+
|
16
|
+
end # Compiler
|
17
|
+
end # Morpher
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Morpher
|
2
|
+
class Compiler
|
3
|
+
# Abstract target indepentand emitter
|
4
|
+
class Emitter
|
5
|
+
include AbstractType, Adamantium::Flat, NodeHelpers, Procto.call(:output)
|
6
|
+
extend NodeHelpers
|
7
|
+
|
8
|
+
# Return output of emitter
|
9
|
+
#
|
10
|
+
# @return [Object]
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
#
|
14
|
+
abstract_method :output
|
15
|
+
|
16
|
+
# Return node
|
17
|
+
#
|
18
|
+
# @return [Node]
|
19
|
+
#
|
20
|
+
# @api private
|
21
|
+
#
|
22
|
+
abstract_method :node
|
23
|
+
private :node
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# Return children
|
28
|
+
#
|
29
|
+
# @return [Array<AST::Node>]
|
30
|
+
#
|
31
|
+
# @api private
|
32
|
+
#
|
33
|
+
def children
|
34
|
+
node.children
|
35
|
+
end
|
36
|
+
|
37
|
+
# Assert number of child nodes
|
38
|
+
#
|
39
|
+
# @return [self]
|
40
|
+
# if assertion is fullfilled
|
41
|
+
#
|
42
|
+
# @raise [NodeError]
|
43
|
+
# otherwise
|
44
|
+
#
|
45
|
+
# @api private
|
46
|
+
#
|
47
|
+
def assert_children_amount(expected_amount)
|
48
|
+
actual_amount = children.length
|
49
|
+
fail Error::NodeChildren.new(node, expected_amount) unless actual_amount.equal?(expected_amount)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Name children
|
53
|
+
#
|
54
|
+
# @return [undefined]
|
55
|
+
#
|
56
|
+
# @api private
|
57
|
+
#
|
58
|
+
# rubocop:disable MethodLength
|
59
|
+
#
|
60
|
+
def self.children(*names)
|
61
|
+
names.each_with_index do |name, index|
|
62
|
+
define_method(name) do
|
63
|
+
children.at(index)
|
64
|
+
end
|
65
|
+
private name
|
66
|
+
end
|
67
|
+
|
68
|
+
define_method(:named_children) do
|
69
|
+
names
|
70
|
+
end
|
71
|
+
private :named_children
|
72
|
+
|
73
|
+
define_method(:remaining_children) do
|
74
|
+
children.drop(names.length)
|
75
|
+
end
|
76
|
+
private :remaining_children
|
77
|
+
end
|
78
|
+
private_class_method :children
|
79
|
+
|
80
|
+
end # Emitter
|
81
|
+
end # Compiler
|
82
|
+
end # Morpher
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Morpher
|
2
|
+
class Compiler
|
3
|
+
|
4
|
+
# Abstract error class for compiler errors
|
5
|
+
class Error < RuntimeError
|
6
|
+
include AbstractType
|
7
|
+
|
8
|
+
# Error raised when node children have incorrect amount
|
9
|
+
class NodeChildren < self
|
10
|
+
include Concord.new(:node, :expected_amount)
|
11
|
+
|
12
|
+
# Return exception message
|
13
|
+
#
|
14
|
+
# @return [String]
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
#
|
18
|
+
def message
|
19
|
+
"Expected #{expected_amount} #{_children} for #{type}, got #{actual_amount}: #{children}"
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# Return inspected type
|
25
|
+
#
|
26
|
+
# @return [String]
|
27
|
+
#
|
28
|
+
# @api private
|
29
|
+
#
|
30
|
+
def type
|
31
|
+
node.type.inspect
|
32
|
+
end
|
33
|
+
|
34
|
+
# Return actual amount of children
|
35
|
+
#
|
36
|
+
# @return [String]
|
37
|
+
#
|
38
|
+
# @api private
|
39
|
+
#
|
40
|
+
def actual_amount
|
41
|
+
children.length
|
42
|
+
end
|
43
|
+
|
44
|
+
# Return children
|
45
|
+
#
|
46
|
+
# @return [Array]
|
47
|
+
#
|
48
|
+
# @api private
|
49
|
+
#
|
50
|
+
def children
|
51
|
+
node.children
|
52
|
+
end
|
53
|
+
|
54
|
+
# Return user firendly children message
|
55
|
+
#
|
56
|
+
# @return [String]
|
57
|
+
#
|
58
|
+
# @api private
|
59
|
+
#
|
60
|
+
def _children
|
61
|
+
expected_amount.equal?(1) ? 'child' : 'children'
|
62
|
+
end
|
63
|
+
|
64
|
+
end # NodeChildren
|
65
|
+
|
66
|
+
# Error raised on compiling unknown nodes
|
67
|
+
class UnknownNode < self
|
68
|
+
include Concord.new(:type)
|
69
|
+
|
70
|
+
# Return exception error message
|
71
|
+
#
|
72
|
+
# @return [String]
|
73
|
+
#
|
74
|
+
# @api private
|
75
|
+
#
|
76
|
+
def message
|
77
|
+
"Node type: #{type.inspect} is unknown"
|
78
|
+
end
|
79
|
+
|
80
|
+
end # UnknownNode
|
81
|
+
|
82
|
+
end # Error
|
83
|
+
end # Compiler
|
84
|
+
end # Morpher
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Morpher
|
2
|
+
class Compiler
|
3
|
+
# Compiler with evaluators as output
|
4
|
+
class Evaluator < self
|
5
|
+
include Concord.new(:evaluators, :emitters)
|
6
|
+
|
7
|
+
# Return evaluator tree for node
|
8
|
+
#
|
9
|
+
# @param [Node] node
|
10
|
+
#
|
11
|
+
# @return [Evalautor]
|
12
|
+
# on success
|
13
|
+
#
|
14
|
+
# @raise [Compiler::Error]
|
15
|
+
# on error
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
#
|
19
|
+
def call(node)
|
20
|
+
evaluator = evaluator(node)
|
21
|
+
emitter = emitter(evaluator)
|
22
|
+
emitter.call(self, evaluator, node)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# Lookup evaluator for node
|
28
|
+
#
|
29
|
+
# @param [Node]
|
30
|
+
#
|
31
|
+
# @return [Class:Evaluator]
|
32
|
+
# if found
|
33
|
+
#
|
34
|
+
# @raise [Error::UnknownNode]
|
35
|
+
# otherwise
|
36
|
+
#
|
37
|
+
# @api private
|
38
|
+
#
|
39
|
+
def evaluator(node)
|
40
|
+
type = node.type
|
41
|
+
evaluators.fetch(type) do
|
42
|
+
fail Error::UnknownNode, type
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Return emitter for evaluator
|
47
|
+
#
|
48
|
+
# @param [Class:Evalautor]
|
49
|
+
#
|
50
|
+
# @return [#call]
|
51
|
+
#
|
52
|
+
# @api private
|
53
|
+
#
|
54
|
+
def emitter(evaluator)
|
55
|
+
emitters.each do |arity, emitter|
|
56
|
+
return emitter if evaluator.ancestors.include?(arity)
|
57
|
+
end
|
58
|
+
fail Error::UnknownNode, evaluator
|
59
|
+
end
|
60
|
+
|
61
|
+
end # Evaluator
|
62
|
+
end # Compiler
|
63
|
+
end # Morpher
|
@@ -0,0 +1,224 @@
|
|
1
|
+
module Morpher
|
2
|
+
class Compiler
|
3
|
+
class Evaluator
|
4
|
+
# Emitter for evaluators
|
5
|
+
class Emitter < Compiler::Emitter
|
6
|
+
include Registry, Concord.new(:compiler, :evaluator_klass, :node)
|
7
|
+
|
8
|
+
# Return output
|
9
|
+
#
|
10
|
+
# @return [Evaluator]
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
#
|
14
|
+
def output
|
15
|
+
validate_node
|
16
|
+
evaluator
|
17
|
+
end
|
18
|
+
memoize :output
|
19
|
+
|
20
|
+
# Validate node
|
21
|
+
#
|
22
|
+
# @return [undefined]
|
23
|
+
# if successful
|
24
|
+
#
|
25
|
+
# @raise [Error]
|
26
|
+
# otherwise
|
27
|
+
#
|
28
|
+
# @api private
|
29
|
+
#
|
30
|
+
abstract_method :validate_node
|
31
|
+
private :validate_node
|
32
|
+
|
33
|
+
# Return evaluator
|
34
|
+
#
|
35
|
+
# @return [Evaluator]
|
36
|
+
#
|
37
|
+
# @api private
|
38
|
+
#
|
39
|
+
abstract_method :evaluator
|
40
|
+
private :evaluator
|
41
|
+
|
42
|
+
# Emitter for nullary non parameterized evaluators
|
43
|
+
class Nullary < self
|
44
|
+
register Morpher::Evaluator::Nullary
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
# Return output
|
49
|
+
#
|
50
|
+
# @return [Evaluator]
|
51
|
+
#
|
52
|
+
# @api private
|
53
|
+
#
|
54
|
+
def evaluator
|
55
|
+
evaluator_klass.new
|
56
|
+
end
|
57
|
+
|
58
|
+
# Validate node
|
59
|
+
#
|
60
|
+
# @return [undefined]
|
61
|
+
# if successful
|
62
|
+
#
|
63
|
+
# @raise [Error]
|
64
|
+
# otherwise
|
65
|
+
#
|
66
|
+
# @api private
|
67
|
+
#
|
68
|
+
def validate_node
|
69
|
+
assert_children_amount(0)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Emitter for nullary parameterized evaluators
|
73
|
+
class Parameterized < self
|
74
|
+
register Morpher::Evaluator::Nullary::Parameterized
|
75
|
+
|
76
|
+
children :param
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
# Return output
|
81
|
+
#
|
82
|
+
# @return [Evaluator]
|
83
|
+
#
|
84
|
+
# @api private
|
85
|
+
#
|
86
|
+
def evaluator
|
87
|
+
evaluator_klass.new(effective_param)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Return effective param
|
91
|
+
#
|
92
|
+
# @return [Object]
|
93
|
+
#
|
94
|
+
# @api private
|
95
|
+
#
|
96
|
+
def effective_param
|
97
|
+
if param.kind_of?(AST::Node) && param.type.equal?(:raw) && param.children.length.equal?(1)
|
98
|
+
param.children.first
|
99
|
+
else
|
100
|
+
param
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Validate node
|
105
|
+
#
|
106
|
+
# @return [undefined]
|
107
|
+
# if successful
|
108
|
+
#
|
109
|
+
# @raise [Error]
|
110
|
+
# otherwise
|
111
|
+
#
|
112
|
+
# @api private
|
113
|
+
#
|
114
|
+
def validate_node
|
115
|
+
assert_children_amount(1)
|
116
|
+
end
|
117
|
+
|
118
|
+
end # Paramterized
|
119
|
+
end # Nullary
|
120
|
+
|
121
|
+
# Emitter for unary evaluators
|
122
|
+
class Unary < self
|
123
|
+
register Morpher::Evaluator::Unary
|
124
|
+
children :operand
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
# Return evaluator
|
129
|
+
#
|
130
|
+
# @return [Evaluator]
|
131
|
+
#
|
132
|
+
# @api private
|
133
|
+
#
|
134
|
+
def evaluator
|
135
|
+
evaluator_klass.new(compiler.call(operand))
|
136
|
+
end
|
137
|
+
|
138
|
+
# Validate node
|
139
|
+
#
|
140
|
+
# @return [undefined]
|
141
|
+
# if successful
|
142
|
+
#
|
143
|
+
# @raise [Error]
|
144
|
+
# otherwise
|
145
|
+
#
|
146
|
+
# @api private
|
147
|
+
#
|
148
|
+
def validate_node
|
149
|
+
assert_children_amount(1)
|
150
|
+
end
|
151
|
+
|
152
|
+
end # Unary
|
153
|
+
|
154
|
+
# Emitter for unary evaluators
|
155
|
+
class Binary < self
|
156
|
+
register Morpher::Evaluator::Binary
|
157
|
+
children :left, :right
|
158
|
+
|
159
|
+
private
|
160
|
+
|
161
|
+
# Return evaluator
|
162
|
+
#
|
163
|
+
# @return [Evaluator]
|
164
|
+
#
|
165
|
+
# @api private
|
166
|
+
#
|
167
|
+
def evaluator
|
168
|
+
evaluator_klass.new(
|
169
|
+
compiler.call(left),
|
170
|
+
compiler.call(right)
|
171
|
+
)
|
172
|
+
end
|
173
|
+
|
174
|
+
# Validate node
|
175
|
+
#
|
176
|
+
# @return [undefined]
|
177
|
+
# if successful
|
178
|
+
#
|
179
|
+
# @raise [Error]
|
180
|
+
# otherwise
|
181
|
+
#
|
182
|
+
# @api private
|
183
|
+
#
|
184
|
+
def validate_node
|
185
|
+
assert_children_amount(2)
|
186
|
+
end
|
187
|
+
|
188
|
+
end # Unary
|
189
|
+
|
190
|
+
# Emitter for nary evaluators
|
191
|
+
class Nary < self
|
192
|
+
register Morpher::Evaluator::Nary
|
193
|
+
|
194
|
+
private
|
195
|
+
|
196
|
+
# Return evaluator
|
197
|
+
#
|
198
|
+
# @return [Evaluator]
|
199
|
+
#
|
200
|
+
# @api private
|
201
|
+
#
|
202
|
+
def evaluator
|
203
|
+
evaluator_klass.new(children.map(&compiler.method(:call)))
|
204
|
+
end
|
205
|
+
|
206
|
+
# Validate node
|
207
|
+
#
|
208
|
+
# @return [undefined]
|
209
|
+
# if successful
|
210
|
+
#
|
211
|
+
# @raise [Error]
|
212
|
+
# otherwise
|
213
|
+
#
|
214
|
+
# @api private
|
215
|
+
#
|
216
|
+
def validate_node
|
217
|
+
end
|
218
|
+
|
219
|
+
end # Nary
|
220
|
+
|
221
|
+
end # Emitter
|
222
|
+
end # Evaluator
|
223
|
+
end # Compiler
|
224
|
+
end # Morpher
|