jaina 0.0.0 → 0.1.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +19 -0
- data/README.md +160 -1
- data/jaina.gemspec +2 -1
- data/lib/jaina/parser/ast/context.rb +98 -0
- data/lib/jaina/parser/ast/evaluator.rb +17 -0
- data/lib/jaina/parser/ast/tree.rb +35 -0
- data/lib/jaina/parser/ast/tree_builder.rb +129 -0
- data/lib/jaina/parser/ast.rb +62 -0
- data/lib/jaina/parser/code_converter/to_postfix_form.rb +167 -0
- data/lib/jaina/parser/code_converter/to_prefix_form.rb +122 -0
- data/lib/jaina/parser/code_converter.rb +28 -0
- data/lib/jaina/parser/expression/operator/abstract/dsl.rb +256 -0
- data/lib/jaina/parser/expression/operator/abstract.rb +67 -0
- data/lib/jaina/parser/expression/operator/and.rb +12 -0
- data/lib/jaina/parser/expression/operator/grouping/dsl.rb +100 -0
- data/lib/jaina/parser/expression/operator/grouping.rb +12 -0
- data/lib/jaina/parser/expression/operator/left_corner.rb +10 -0
- data/lib/jaina/parser/expression/operator/non_terminal.rb +25 -0
- data/lib/jaina/parser/expression/operator/not.rb +12 -0
- data/lib/jaina/parser/expression/operator/or.rb +12 -0
- data/lib/jaina/parser/expression/operator/right_corner.rb +10 -0
- data/lib/jaina/parser/expression/operator/terminal.rb +25 -0
- data/lib/jaina/parser/expression/operator.rb +15 -0
- data/lib/jaina/parser/expression/registry/access_interface_mixin.rb +49 -0
- data/lib/jaina/parser/expression/registry.rb +127 -0
- data/lib/jaina/parser/expression.rb +87 -0
- data/lib/jaina/parser/tokenizer.rb +37 -0
- data/lib/jaina/parser.rb +44 -0
- data/lib/jaina/version.rb +5 -1
- data/lib/jaina.rb +58 -4
- metadata +29 -2
@@ -0,0 +1,167 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.1.0
|
5
|
+
class Jaina::Parser::CodeConverter::ToPostfixForm
|
6
|
+
# @api private
|
7
|
+
# @since 0.1.0
|
8
|
+
extend Forwardable
|
9
|
+
|
10
|
+
class << self
|
11
|
+
# @param program [String]
|
12
|
+
# @return [String]
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
# @since 0.1.0
|
16
|
+
def call(program)
|
17
|
+
new(program).call
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# @since 0.1.0
|
22
|
+
def_delegators Jaina::Parser::Expression,
|
23
|
+
:non_terminal?,
|
24
|
+
:terminal?,
|
25
|
+
:group_opener?,
|
26
|
+
:group_closener?
|
27
|
+
|
28
|
+
# @param program [String]
|
29
|
+
# @return [void]
|
30
|
+
#
|
31
|
+
# @api private
|
32
|
+
# @since 0.1.0
|
33
|
+
def initialize(program)
|
34
|
+
@program = program.dup.tap(&:freeze)
|
35
|
+
@tokens = Jaina::Parser::Tokenizer.tokenize(program)
|
36
|
+
end
|
37
|
+
|
38
|
+
# @return [String]
|
39
|
+
#
|
40
|
+
# @api private
|
41
|
+
# @since 0.1.0
|
42
|
+
def call
|
43
|
+
to_postfix_form
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
# @return [String]
|
49
|
+
#
|
50
|
+
# @api private
|
51
|
+
# @since 0.1.0
|
52
|
+
attr_reader :program
|
53
|
+
|
54
|
+
# @return [Array<String>]
|
55
|
+
#
|
56
|
+
# @api private
|
57
|
+
# @since 0.1.0
|
58
|
+
attr_reader :tokens
|
59
|
+
|
60
|
+
# @return [String]
|
61
|
+
#
|
62
|
+
# @api private
|
63
|
+
# @since 0.1.0
|
64
|
+
def to_postfix_form
|
65
|
+
final_expression = []
|
66
|
+
structure_operators = []
|
67
|
+
token_series = tokens.map(&:dup)
|
68
|
+
|
69
|
+
until token_series.empty?
|
70
|
+
current_token = token_series.shift
|
71
|
+
|
72
|
+
case
|
73
|
+
when non_terminal?(current_token)
|
74
|
+
process_non_terminal_token(final_expression, structure_operators, current_token)
|
75
|
+
when group_opener?(current_token)
|
76
|
+
process_group_opening_token(final_expression, structure_operators, current_token)
|
77
|
+
when group_closener?(current_token)
|
78
|
+
process_group_closing_token(final_expression, structure_operators, current_token)
|
79
|
+
when terminal?(current_token)
|
80
|
+
process_terminal_token(final_expression, structure_operators, current_token)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
finish_final_expression(final_expression, structure_operators, current_token)
|
85
|
+
|
86
|
+
# NOTE: build postfixed program string
|
87
|
+
Jaina::Parser::Tokenizer.join(final_expression)
|
88
|
+
end
|
89
|
+
|
90
|
+
# @param final_expression [Array<String>]
|
91
|
+
# @param structure_operators [Array<String>]
|
92
|
+
# @param current_token [String]
|
93
|
+
# @return [void]
|
94
|
+
#
|
95
|
+
# @api private
|
96
|
+
# @since 0.1.0
|
97
|
+
def process_non_terminal_token(final_expression, structure_operators, current_token)
|
98
|
+
if structure_operators.any? # NOTE: check assocaitivity with potential next token
|
99
|
+
potential_second_token = structure_operators.last
|
100
|
+
|
101
|
+
if non_terminal?(potential_second_token)
|
102
|
+
current_expression = Jaina::Parser::Expression.fetch(current_token)
|
103
|
+
next_expression = Jaina::Parser::Expression.fetch(potential_second_token)
|
104
|
+
|
105
|
+
# NOTE: form infix to postfix form switching
|
106
|
+
final_expression.push(structure_operators.pop) if current_expression.lower?(next_expression)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
structure_operators.push(current_token)
|
111
|
+
end
|
112
|
+
|
113
|
+
# @param final_expression [Array<String>]
|
114
|
+
# @param structure_operators [Array<String>]
|
115
|
+
# @param current_token [String]
|
116
|
+
# @return [void]
|
117
|
+
#
|
118
|
+
# @api private
|
119
|
+
# @since 0.1.0
|
120
|
+
def process_group_opening_token(final_expression, structure_operators, current_token)
|
121
|
+
# NOTE: remember group opening operator
|
122
|
+
structure_operators.push(current_token)
|
123
|
+
end
|
124
|
+
|
125
|
+
# @param final_expression [Array<String>]
|
126
|
+
# @param structure_operators [Array<String>]
|
127
|
+
# @param current_token [String]
|
128
|
+
# @return [void]
|
129
|
+
#
|
130
|
+
# @api private
|
131
|
+
# @since 0.1.0
|
132
|
+
def process_group_closing_token(final_expression, structure_operators, current_token)
|
133
|
+
until group_opener?(structure_operators.last)
|
134
|
+
# NOTE: push all tokens to the final expression
|
135
|
+
final_expression.push(structure_operators.pop)
|
136
|
+
end
|
137
|
+
|
138
|
+
# NOTE: drop closing operator
|
139
|
+
structure_operators.pop
|
140
|
+
end
|
141
|
+
|
142
|
+
# @param final_expression [Array<String>]
|
143
|
+
# @param structure_operators [Array<String>]
|
144
|
+
# @param current_token [String]
|
145
|
+
# @return [void]
|
146
|
+
#
|
147
|
+
# @api private
|
148
|
+
# @since 0.1.0
|
149
|
+
def process_terminal_token(final_expression, structure_operators, current_token)
|
150
|
+
# NOTE: push terminal expression to the final expression
|
151
|
+
final_expression.push(current_token)
|
152
|
+
end
|
153
|
+
|
154
|
+
# @param final_expression [Array<String>]
|
155
|
+
# @param structure_operators [Array<String>]
|
156
|
+
# @param current_token [String]
|
157
|
+
# @return [void]
|
158
|
+
#
|
159
|
+
# @api private
|
160
|
+
# @since 0.1.0
|
161
|
+
def finish_final_expression(final_expression, structure_operators, current_token)
|
162
|
+
# NOTE: fill the rest tokens to the final expression
|
163
|
+
until structure_operators.empty?
|
164
|
+
final_expression.push(structure_operators.pop)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.1.0
|
5
|
+
class Jaina::Parser::CodeConverter::ToPrefixForm
|
6
|
+
# @since 0.1.0
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
class << self
|
10
|
+
# @param program [String]
|
11
|
+
# @return [String]
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
# @since 0.1.0
|
15
|
+
def call(program)
|
16
|
+
new(program).call
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# @since 0.1.0
|
21
|
+
def_delegators Jaina::Parser::Expression, :terminal?, :non_terminal?
|
22
|
+
|
23
|
+
# @param program [String]
|
24
|
+
# @return [void]
|
25
|
+
#
|
26
|
+
# @api private
|
27
|
+
# @since 0.1.0
|
28
|
+
def initialize(program)
|
29
|
+
@program = program.dup.tap(&:freeze)
|
30
|
+
@postfix_form = Jaina::Parser::CodeConverter::ToPostfixForm.call(@program)
|
31
|
+
@tokens = Jaina::Parser::Tokenizer.tokenize(@postfix_form)
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [String]
|
35
|
+
#
|
36
|
+
# @api private
|
37
|
+
# @since 0.1.0
|
38
|
+
def call
|
39
|
+
to_prefix_form
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
# @return [String]
|
45
|
+
#
|
46
|
+
# @api private
|
47
|
+
# @since 0.1.0
|
48
|
+
attr_reader :program
|
49
|
+
|
50
|
+
# @return [String]
|
51
|
+
#
|
52
|
+
# @api private
|
53
|
+
# @since 0.1.0
|
54
|
+
attr_reader :postfix_form
|
55
|
+
|
56
|
+
# @return [Array<String>]
|
57
|
+
#
|
58
|
+
# @api private
|
59
|
+
# @since 0.1.0
|
60
|
+
attr_reader :tokens
|
61
|
+
|
62
|
+
# @return [String]
|
63
|
+
#
|
64
|
+
# @api private
|
65
|
+
# @since 0.1.0
|
66
|
+
def to_prefix_form
|
67
|
+
token_series = tokens.map(&:dup)
|
68
|
+
expression_stack = []
|
69
|
+
|
70
|
+
until token_series.empty?
|
71
|
+
current_token = token_series.shift
|
72
|
+
|
73
|
+
case
|
74
|
+
when terminal?(current_token)
|
75
|
+
process_terminal_token(current_token, expression_stack)
|
76
|
+
when non_terminal?(current_token)
|
77
|
+
process_non_terminal_token(current_token, expression_stack)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# NOTE: build prefixed program string
|
82
|
+
Jaina::Parser::Tokenizer.join(expression_stack)
|
83
|
+
end
|
84
|
+
|
85
|
+
# @param current_token [String]
|
86
|
+
# @param expression_stack [Array<String>]
|
87
|
+
# @return [void]
|
88
|
+
#
|
89
|
+
# @api private
|
90
|
+
# @since 0.1.0
|
91
|
+
def process_terminal_token(current_token, expression_stack)
|
92
|
+
expression_stack.push(current_token)
|
93
|
+
end
|
94
|
+
|
95
|
+
# @param current_token [String]
|
96
|
+
# @param expression_stack [Array<String>]
|
97
|
+
# @return [void]
|
98
|
+
#
|
99
|
+
# @api private
|
100
|
+
# @since 0.1.0
|
101
|
+
def process_non_terminal_token(current_token, expression_stack)
|
102
|
+
expression = Jaina::Parser::Expression.fetch(current_token)
|
103
|
+
|
104
|
+
case # TODO: dry
|
105
|
+
when expression.acts_as_binary_term?
|
106
|
+
first_operand = expression_stack.pop
|
107
|
+
second_operand = expression_stack.pop
|
108
|
+
|
109
|
+
prefixed_expression_parts = [expression.token, second_operand, first_operand]
|
110
|
+
prefixed_expression = Jaina::Parser::Tokenizer.join(prefixed_expression_parts)
|
111
|
+
|
112
|
+
expression_stack.push(prefixed_expression)
|
113
|
+
when expression.acts_as_unary_term?
|
114
|
+
operand = expression_stack.pop
|
115
|
+
|
116
|
+
prefixed_expression_parts = [expression.token, operand]
|
117
|
+
prefixed_expression = Jaina::Parser::Tokenizer.join(prefixed_expression_parts)
|
118
|
+
|
119
|
+
expression_stack.push(prefixed_expression)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.1.0
|
5
|
+
class Jaina::Parser::CodeConverter
|
6
|
+
require_relative './code_converter/to_postfix_form'
|
7
|
+
require_relative './code_converter/to_prefix_form'
|
8
|
+
|
9
|
+
class << self
|
10
|
+
# @param program [String]
|
11
|
+
# @return [String]
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
# @since 0.1.0
|
15
|
+
def to_postfix_form(program)
|
16
|
+
ToPrefixForm.call(program)
|
17
|
+
end
|
18
|
+
|
19
|
+
# @param program [String]
|
20
|
+
# @return [String]
|
21
|
+
#
|
22
|
+
# @api private
|
23
|
+
# @since 0.1.0
|
24
|
+
def to_prefix_form(program)
|
25
|
+
ToPrefixForm.call(program)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,256 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.1.0
|
5
|
+
module Jaina::Parser::Expression::Operator::Abstract::DSL
|
6
|
+
# @since 0.1.0
|
7
|
+
Error = Class.new(StandardError)
|
8
|
+
# @since 0.1.0
|
9
|
+
IncorrectTokenError = Class.new(Error)
|
10
|
+
# @since 0.1.0
|
11
|
+
IncorrectPrecedenceLevelError = Class.new(Error)
|
12
|
+
# @since 0.1.0
|
13
|
+
IncorrectAssociativityDirectionError = Class.new(Error)
|
14
|
+
|
15
|
+
# @return [Symbol]
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
# @since 0.1.0
|
19
|
+
LEFT_ASSOC = :left
|
20
|
+
|
21
|
+
# @return [Symbol]
|
22
|
+
#
|
23
|
+
# @api private
|
24
|
+
# @since 0.1.0
|
25
|
+
RIGHT_ASSOC = :right
|
26
|
+
|
27
|
+
class << self
|
28
|
+
# @param base_klass [Class]
|
29
|
+
# @return [void]
|
30
|
+
#
|
31
|
+
# @api private
|
32
|
+
# @since 0.1.0
|
33
|
+
def included(base_klass)
|
34
|
+
base_klass.instance_variable_set(:@token, nil)
|
35
|
+
base_klass.instance_variable_set(:@precedence_level, nil)
|
36
|
+
base_klass.instance_variable_set(:@associativity_direction, nil)
|
37
|
+
base_klass.instance_variable_set(:@acts_as_binary_term, false)
|
38
|
+
base_klass.instance_variable_set(:@acts_as_unary_term, false)
|
39
|
+
|
40
|
+
base_klass.extend ClassMethods
|
41
|
+
base_klass.include InstanceMethods
|
42
|
+
base_klass.singleton_class.prepend(ClassInheritance)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# @api private
|
47
|
+
# @since 0.1.0
|
48
|
+
module ClassInheritance
|
49
|
+
# @param child_klass [Class]
|
50
|
+
# @return [void]
|
51
|
+
#
|
52
|
+
# @api private
|
53
|
+
# @since 0.1.0
|
54
|
+
def inherited(child_klass)
|
55
|
+
child_klass.instance_variable_set(
|
56
|
+
:@token,
|
57
|
+
instance_variable_get(:@token)
|
58
|
+
)
|
59
|
+
|
60
|
+
child_klass.instance_variable_set(
|
61
|
+
:@precedence_level,
|
62
|
+
instance_variable_get(:@precedence_level)
|
63
|
+
)
|
64
|
+
|
65
|
+
child_klass.instance_variable_set(
|
66
|
+
:@associativity_direction,
|
67
|
+
instance_variable_get(:@associativity_direction)
|
68
|
+
)
|
69
|
+
|
70
|
+
child_klass.instance_variable_set(
|
71
|
+
:@acts_as_binary_term,
|
72
|
+
instance_variable_get(:@acts_as_binary_term)
|
73
|
+
)
|
74
|
+
|
75
|
+
child_klass.instance_variable_set(
|
76
|
+
:@acts_as_unary_term,
|
77
|
+
instance_variable_get(:@acts_as_unary_term)
|
78
|
+
)
|
79
|
+
|
80
|
+
super
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# @api private
|
85
|
+
# @since 0.1.0
|
86
|
+
module ClassMethods
|
87
|
+
# @param term [String, NilClass]
|
88
|
+
# @return [String, NilClass]
|
89
|
+
#
|
90
|
+
# @api private
|
91
|
+
# @since 0.1.0
|
92
|
+
def token(term = nil)
|
93
|
+
unless term.is_a?(String) || term.is_a?(NilClass)
|
94
|
+
raise IncorrectTokenError, 'Token should be a type of string'
|
95
|
+
end
|
96
|
+
|
97
|
+
@token = term unless term.nil?
|
98
|
+
@token
|
99
|
+
end
|
100
|
+
|
101
|
+
# @param level [Integer, NilClass]
|
102
|
+
# @return [Integer, NilClass]
|
103
|
+
#
|
104
|
+
# @api private
|
105
|
+
# @since 0.1.0
|
106
|
+
def precedence_level(level = nil)
|
107
|
+
unless level.is_a?(Integer) || level.is_a?(NilClass)
|
108
|
+
raise IncorrectPrecedenceLevelError, 'Precendence level should be a type of integer'
|
109
|
+
end
|
110
|
+
|
111
|
+
@precedence_level = level unless level.nil?
|
112
|
+
@precedence_level
|
113
|
+
end
|
114
|
+
|
115
|
+
# @param assoc [String, NilClass]
|
116
|
+
# @return [String, NilClass]
|
117
|
+
#
|
118
|
+
# @api private
|
119
|
+
# @since 0.1.0
|
120
|
+
def associativity_direction(assoc = nil)
|
121
|
+
unless assoc.is_a?(NilClass) || assoc == LEFT_ASSOC || assoc == RIGHT_ASSOC
|
122
|
+
raise(
|
123
|
+
IncorrectAssociativityDirectionError,
|
124
|
+
"Associativity direction can be :#{LEFT_ASSOC} or :#{RIGHT_ASSOC}"
|
125
|
+
)
|
126
|
+
end
|
127
|
+
|
128
|
+
@associativity_direction = assoc unless assoc.nil?
|
129
|
+
@associativity_direction
|
130
|
+
end
|
131
|
+
|
132
|
+
# @return [void]
|
133
|
+
#
|
134
|
+
# @api private
|
135
|
+
# @since 0.1.0
|
136
|
+
def acts_as_binary_term
|
137
|
+
@acts_as_binary_term = true
|
138
|
+
end
|
139
|
+
|
140
|
+
# @return [void]
|
141
|
+
#
|
142
|
+
# @api private
|
143
|
+
# @since 0.1.0
|
144
|
+
def acts_as_unary_term
|
145
|
+
@acts_as_unary_term = true
|
146
|
+
end
|
147
|
+
|
148
|
+
# @return [void]
|
149
|
+
#
|
150
|
+
# @api private
|
151
|
+
# @since 0.1.0
|
152
|
+
def acts_as_binary_term?
|
153
|
+
@acts_as_binary_term
|
154
|
+
end
|
155
|
+
|
156
|
+
# @return [void]
|
157
|
+
#
|
158
|
+
# @api private
|
159
|
+
# @since 0.1.0
|
160
|
+
def acts_as_unary_term?
|
161
|
+
@acts_as_unary_term
|
162
|
+
end
|
163
|
+
|
164
|
+
# @return [Boolean]
|
165
|
+
#
|
166
|
+
# @api private
|
167
|
+
# @since 0.1.0
|
168
|
+
def terminal?
|
169
|
+
false
|
170
|
+
end
|
171
|
+
|
172
|
+
# @return [Boolean]
|
173
|
+
#
|
174
|
+
# @api private
|
175
|
+
# @since 0.1.0
|
176
|
+
def non_terminal?
|
177
|
+
false
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# @api private
|
182
|
+
# @since 0.1.0
|
183
|
+
module InstanceMethods
|
184
|
+
# @return [String, NilClass]
|
185
|
+
#
|
186
|
+
# @api private
|
187
|
+
# @since 0.1.0
|
188
|
+
def token
|
189
|
+
self.class.token
|
190
|
+
end
|
191
|
+
|
192
|
+
# @return [Integer, NilClass]
|
193
|
+
#
|
194
|
+
# @api private
|
195
|
+
# @since 0.1.0
|
196
|
+
def precedence_level
|
197
|
+
self.class.precedence_level
|
198
|
+
end
|
199
|
+
|
200
|
+
# @return [Symbol, NilClass]
|
201
|
+
#
|
202
|
+
# @api private
|
203
|
+
# @since 0.1.0
|
204
|
+
def associativity_direction
|
205
|
+
self.class.associativity_direction
|
206
|
+
end
|
207
|
+
|
208
|
+
# @return [Boolean]
|
209
|
+
#
|
210
|
+
# @api private
|
211
|
+
# @since 0.1.0
|
212
|
+
def acts_as_group_closener?
|
213
|
+
self.class.acts_as_group_closener?
|
214
|
+
end
|
215
|
+
|
216
|
+
# @return [Boolean]
|
217
|
+
#
|
218
|
+
# @api private
|
219
|
+
# @since 0.1.0
|
220
|
+
def acts_as_group_opener?
|
221
|
+
self.class.acts_as_group_opener?
|
222
|
+
end
|
223
|
+
|
224
|
+
# @return [Boolean]
|
225
|
+
#
|
226
|
+
# @api private
|
227
|
+
# @since 0.1.0
|
228
|
+
def acts_as_binary_term?
|
229
|
+
self.class.acts_as_binary_term?
|
230
|
+
end
|
231
|
+
|
232
|
+
# @return [Boolean]
|
233
|
+
#
|
234
|
+
# @api private
|
235
|
+
# @since 0.1.0
|
236
|
+
def acts_as_unary_term?
|
237
|
+
self.class.acts_as_unary_term?
|
238
|
+
end
|
239
|
+
|
240
|
+
# @return [Boolean]
|
241
|
+
#
|
242
|
+
# @api private
|
243
|
+
# @since 0.1.0
|
244
|
+
def terminal?
|
245
|
+
self.class.terminal?
|
246
|
+
end
|
247
|
+
|
248
|
+
# @return [Boolean]
|
249
|
+
#
|
250
|
+
# @api private
|
251
|
+
# @since 0.1.0
|
252
|
+
def non_terminal?
|
253
|
+
self.class.non_terminal?
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.1.0
|
5
|
+
class Jaina::Parser::Expression::Operator::Abstract
|
6
|
+
require_relative './abstract/dsl'
|
7
|
+
|
8
|
+
# @since 0.1.0
|
9
|
+
include DSL
|
10
|
+
# @since 0.1.0
|
11
|
+
Error = Class.new(StandardError)
|
12
|
+
# @since 0.1.0
|
13
|
+
InompatibleDirectionComparisonError = Class.new(Error)
|
14
|
+
|
15
|
+
class << self
|
16
|
+
# @param another_operator [Class<Jaina::Parser::Expression::Operator::Abstract>]
|
17
|
+
# @return [Boolean]
|
18
|
+
#
|
19
|
+
# @raise [InompatibleDirectionComparisonError]
|
20
|
+
#
|
21
|
+
# @api private
|
22
|
+
# @since 0.1.0
|
23
|
+
def lower?(another_operator)
|
24
|
+
raise(
|
25
|
+
InompatibleDirectionComparisonError,
|
26
|
+
"Trying to compare non-comparable terms `#{token}` and `#{another_operator.token}`"
|
27
|
+
) if associativity_direction.nil? || another_operator.associativity_direction.nil?
|
28
|
+
|
29
|
+
if associativity_direction == Jaina::Parser::Expression::Operator::Abstract::DSL::LEFT_ASSOC
|
30
|
+
associativity_direction <= another_operator.associativity_direction
|
31
|
+
else
|
32
|
+
associativity_direction < another_operator.associativity_direction
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# @return [Array<Jaina::Parser::Expressions::Operator::Abstract>]
|
38
|
+
#
|
39
|
+
# @api private
|
40
|
+
# @since 0.1.0
|
41
|
+
attr_reader :expressions
|
42
|
+
|
43
|
+
# @param expressions [Array<Jaina::Parser::Expression::Operator::Abstract>]
|
44
|
+
# @return [void]
|
45
|
+
#
|
46
|
+
# @api private
|
47
|
+
# @since 0.1.0
|
48
|
+
def initialize(*expressions)
|
49
|
+
@expressions = expressions
|
50
|
+
end
|
51
|
+
|
52
|
+
# @param context [Any]
|
53
|
+
# @return [Any]
|
54
|
+
#
|
55
|
+
# @api private
|
56
|
+
# @since 0.1.0
|
57
|
+
def evaluate(context); end
|
58
|
+
|
59
|
+
# @param another_operator [Class<Jaina::Parser::Expression::Operator::Abstract>]
|
60
|
+
# @return [Boolean]
|
61
|
+
#
|
62
|
+
# @api private
|
63
|
+
# @since 0.1.0
|
64
|
+
def lower(another_operator)
|
65
|
+
self.class.lower(another_operator)
|
66
|
+
end
|
67
|
+
end
|