template-ruby-parser 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.overcommit.yml +4 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +32 -0
- data/bin/code-parser +27 -0
- data/bin/format +3 -0
- data/bin/template-parser +27 -0
- data/docs/class.code +9 -0
- data/docs/meetup.code +14 -0
- data/docs/rain.code +23 -0
- data/docs/slack.code +17 -0
- data/docs/stripe.code +7 -0
- data/docs/twitter.code +7 -0
- data/lib/code/parser/addition.rb +13 -0
- data/lib/code/parser/and_operator.rb +13 -0
- data/lib/code/parser/bitwise_and.rb +13 -0
- data/lib/code/parser/bitwise_or.rb +13 -0
- data/lib/code/parser/boolean.rb +13 -0
- data/lib/code/parser/call.rb +174 -0
- data/lib/code/parser/chained_call.rb +41 -0
- data/lib/code/parser/class.rb +56 -0
- data/lib/code/parser/code.rb +20 -0
- data/lib/code/parser/comments.rb +46 -0
- data/lib/code/parser/dictionnary.rb +48 -0
- data/lib/code/parser/equal.rb +39 -0
- data/lib/code/parser/equality.rb +20 -0
- data/lib/code/parser/error/syntax_error.rb +36 -0
- data/lib/code/parser/error.rb +6 -0
- data/lib/code/parser/function.rb +109 -0
- data/lib/code/parser/greater_than.rb +13 -0
- data/lib/code/parser/group.rb +15 -0
- data/lib/code/parser/identifier.rb +54 -0
- data/lib/code/parser/if.rb +81 -0
- data/lib/code/parser/if_modifier.rb +39 -0
- data/lib/code/parser/list.rb +20 -0
- data/lib/code/parser/multiplication.rb +13 -0
- data/lib/code/parser/negation.rb +18 -0
- data/lib/code/parser/not_keyword.rb +24 -0
- data/lib/code/parser/nothing.rb +13 -0
- data/lib/code/parser/number.rb +39 -0
- data/lib/code/parser/operation.rb +44 -0
- data/lib/code/parser/or_keyword.rb +13 -0
- data/lib/code/parser/or_operator.rb +13 -0
- data/lib/code/parser/power.rb +33 -0
- data/lib/code/parser/range.rb +13 -0
- data/lib/code/parser/rescue.rb +38 -0
- data/lib/code/parser/shift.rb +13 -0
- data/lib/code/parser/statement.rb +9 -0
- data/lib/code/parser/string.rb +61 -0
- data/lib/code/parser/ternary.rb +73 -0
- data/lib/code/parser/unary_minus.rb +23 -0
- data/lib/code/parser/while.rb +36 -0
- data/lib/code/parser.rb +237 -0
- data/lib/code-ruby-parser.rb +7 -0
- data/lib/code.rb +2 -0
- data/lib/template/parser.rb +32 -0
- data/lib/template-ruby-parser.rb +7 -0
- data/lib/template.rb +2 -0
- data/spec/code/parser/addition_spec.rb +26 -0
- data/spec/code/parser/and_operator_spec.rb +26 -0
- data/spec/code/parser/bitwise_and_spec.rb +26 -0
- data/spec/code/parser/bitwise_or_spec.rb +26 -0
- data/spec/code/parser/boolean_spec.rb +13 -0
- data/spec/code/parser/call_spec.rb +52 -0
- data/spec/code/parser/chained_call_spec.rb +33 -0
- data/spec/code/parser/class_spec.rb +32 -0
- data/spec/code/parser/code_spec.rb +13 -0
- data/spec/code/parser/dictionnary_spec.rb +40 -0
- data/spec/code/parser/equal_spec.rb +42 -0
- data/spec/code/parser/equality_spec.rb +26 -0
- data/spec/code/parser/function_spec.rb +43 -0
- data/spec/code/parser/greater_than_spec.rb +26 -0
- data/spec/code/parser/group_spec.rb +13 -0
- data/spec/code/parser/if_modifier_spec.rb +26 -0
- data/spec/code/parser/if_spec.rb +39 -0
- data/spec/code/parser/list_spec.rb +27 -0
- data/spec/code/parser/multiplication_spec.rb +26 -0
- data/spec/code/parser/negation_spec.rb +13 -0
- data/spec/code/parser/not_keyword_spec.rb +21 -0
- data/spec/code/parser/nothing_spec.rb +20 -0
- data/spec/code/parser/number_spec.rb +24 -0
- data/spec/code/parser/or_keyword_spec.rb +26 -0
- data/spec/code/parser/or_operator_spec.rb +26 -0
- data/spec/code/parser/power_spec.rb +21 -0
- data/spec/code/parser/range_spec.rb +21 -0
- data/spec/code/parser/rescue_spec.rb +26 -0
- data/spec/code/parser/shift_spec.rb +26 -0
- data/spec/code/parser/string_spec.rb +27 -0
- data/spec/code/parser/ternary_spec.rb +26 -0
- data/spec/code/parser/unary_minus_spec.rb +21 -0
- data/spec/code/parser/while_spec.rb +32 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/template/parser_spec.rb +13 -0
- data/template-ruby-parser.gemspec +16 -0
- metadata +171 -0
@@ -0,0 +1,39 @@
|
|
1
|
+
class Code
|
2
|
+
class Parser
|
3
|
+
class Equal < ::Code::Parser
|
4
|
+
def parse
|
5
|
+
left = parse_subclass(::Code::Parser::Rescue)
|
6
|
+
|
7
|
+
previous_cursor = cursor
|
8
|
+
|
9
|
+
comments_before = parse_comments
|
10
|
+
|
11
|
+
if operator = match(EQUALS)
|
12
|
+
previous_cursor = cursor
|
13
|
+
comments_after = parse_comments
|
14
|
+
|
15
|
+
right = parse_subclass(::Code::Parser::Equal)
|
16
|
+
|
17
|
+
if right
|
18
|
+
{
|
19
|
+
equal: {
|
20
|
+
left: left,
|
21
|
+
right: right,
|
22
|
+
comments_before: comments_before,
|
23
|
+
comments_after: comments_after
|
24
|
+
}.compact
|
25
|
+
}
|
26
|
+
else
|
27
|
+
@cursor = previous_cursor
|
28
|
+
buffer!
|
29
|
+
{ equal: { left: left, comments_before: comments_before } }
|
30
|
+
end
|
31
|
+
else
|
32
|
+
@cursor = previous_cursor
|
33
|
+
buffer!
|
34
|
+
left
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class Code
|
2
|
+
class Parser
|
3
|
+
class Equality < ::Code::Parser
|
4
|
+
def parse
|
5
|
+
parse_subclass(
|
6
|
+
::Code::Parser::Operation,
|
7
|
+
operators: [
|
8
|
+
EQUAL + EQUAL + EQUAL,
|
9
|
+
LESSER + EQUAL + GREATER,
|
10
|
+
EQUAL + TILDE,
|
11
|
+
EXCLAMATION_POINT + TILDE,
|
12
|
+
EQUAL + EQUAL,
|
13
|
+
EXCLAMATION_POINT + EQUAL
|
14
|
+
],
|
15
|
+
subclass: ::Code::Parser::While
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class Code
|
2
|
+
class Parser
|
3
|
+
class Error
|
4
|
+
class SyntaxError < ::Code::Parser::Error
|
5
|
+
def initialize(
|
6
|
+
message,
|
7
|
+
input:,
|
8
|
+
line:,
|
9
|
+
column:,
|
10
|
+
offset_lines:,
|
11
|
+
offset_columns:
|
12
|
+
)
|
13
|
+
@message = message
|
14
|
+
@input = input
|
15
|
+
@line = line
|
16
|
+
@column = column
|
17
|
+
@offset_lines = offset_lines
|
18
|
+
@offset_columns = offset_columns
|
19
|
+
end
|
20
|
+
|
21
|
+
def message
|
22
|
+
@message + "\n\n" + line_message + "\n" + " " * column +
|
23
|
+
"^" * offset_columns
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def line_message
|
29
|
+
input.lines[line..(line + offset_lines)].join
|
30
|
+
end
|
31
|
+
|
32
|
+
attr_reader :input, :line, :column, :offset_lines, :offset_columns
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
class Code
|
2
|
+
class Parser
|
3
|
+
class Function < ::Code::Parser
|
4
|
+
def parse
|
5
|
+
return parse_next unless next?(OPENING_PARENTHESIS)
|
6
|
+
previous_cursor = cursor
|
7
|
+
match(OPENING_PARENTHESIS)
|
8
|
+
parameters_comments = parse_comments
|
9
|
+
parameters = parse_parameters
|
10
|
+
match(CLOSING_PARENTHESIS)
|
11
|
+
comments_before = parse_comments
|
12
|
+
if match(EQUAL + GREATER)
|
13
|
+
comments_after = parse_comments
|
14
|
+
if match(OPENING_CURLY_BRACKET)
|
15
|
+
body = parse_code
|
16
|
+
match(CLOSING_CURLY_BRACKET)
|
17
|
+
{
|
18
|
+
function: {
|
19
|
+
parameters: parameters,
|
20
|
+
body: body,
|
21
|
+
parameters_comments: parameters_comments,
|
22
|
+
comments_before: comments_before,
|
23
|
+
comments_after: comments_after
|
24
|
+
}.compact
|
25
|
+
}
|
26
|
+
else
|
27
|
+
buffer!
|
28
|
+
@cursor = previous_cursor
|
29
|
+
parse_next
|
30
|
+
end
|
31
|
+
else
|
32
|
+
buffer!
|
33
|
+
@cursor = previous_cursor
|
34
|
+
parse_next
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def parse_next
|
39
|
+
parse_subclass(::Code::Parser::ChainedCall)
|
40
|
+
end
|
41
|
+
|
42
|
+
def parse_parameters
|
43
|
+
parameters = []
|
44
|
+
|
45
|
+
parameters << (parse_keyword_parameter || parse_regular_parameter)
|
46
|
+
|
47
|
+
while match(COMMA) && !end_of_input?
|
48
|
+
parameters << (parse_keyword_parameter || parse_regular_parameter)
|
49
|
+
end
|
50
|
+
|
51
|
+
parameters.compact.empty? ? nil : parameters.compact
|
52
|
+
end
|
53
|
+
|
54
|
+
def parse_keyword_parameter
|
55
|
+
previous_cursor = cursor
|
56
|
+
|
57
|
+
comments_before = parse_comments
|
58
|
+
|
59
|
+
key = parse_subclass(::Code::Parser::Identifier)
|
60
|
+
|
61
|
+
comments_after = parse_comments
|
62
|
+
|
63
|
+
if key && (match(COLON) || match(EQUAL + GREATER))
|
64
|
+
default = parse_code
|
65
|
+
|
66
|
+
{
|
67
|
+
default: default,
|
68
|
+
keyword: true,
|
69
|
+
comments_before: comments_before,
|
70
|
+
comments_after: comments_after,
|
71
|
+
**key
|
72
|
+
}.compact
|
73
|
+
else
|
74
|
+
@cursor = previous_cursor
|
75
|
+
buffer!
|
76
|
+
return
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def parse_regular_parameter
|
81
|
+
previous_cursor = cursor
|
82
|
+
comments_before = parse_comments
|
83
|
+
|
84
|
+
identifier = parse_subclass(::Code::Parser::Identifier)
|
85
|
+
|
86
|
+
comments_after = parse_comments
|
87
|
+
|
88
|
+
if identifier
|
89
|
+
if match(EQUAL)
|
90
|
+
default = parse_code
|
91
|
+
else
|
92
|
+
default = nil
|
93
|
+
end
|
94
|
+
|
95
|
+
{
|
96
|
+
default: default,
|
97
|
+
comments_before: comments_before,
|
98
|
+
comments_after: comments_after,
|
99
|
+
**identifier
|
100
|
+
}.compact
|
101
|
+
else
|
102
|
+
@cursor = previous_cursor
|
103
|
+
buffer!
|
104
|
+
return
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Code
|
2
|
+
class Parser
|
3
|
+
class GreaterThan < ::Code::Parser
|
4
|
+
def parse
|
5
|
+
parse_subclass(
|
6
|
+
::Code::Parser::Operation,
|
7
|
+
operators: [GREATER + EQUAL, LESSER + EQUAL, GREATER, LESSER],
|
8
|
+
subclass: ::Code::Parser::BitwiseOr
|
9
|
+
)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Code
|
2
|
+
class Parser
|
3
|
+
class Group < ::Code::Parser
|
4
|
+
def parse
|
5
|
+
if match(OPENING_PARENTHESIS)
|
6
|
+
code = parse_subclass(::Code::Parser::Code)
|
7
|
+
match(CLOSING_PARENTHESIS)
|
8
|
+
{ group: code }
|
9
|
+
else
|
10
|
+
parse_subclass(::Code::Parser::Call)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
class Code
|
2
|
+
class Parser
|
3
|
+
class Identifier < ::Code::Parser
|
4
|
+
def initialize(input, simple: false, **kargs)
|
5
|
+
super(input, **kargs)
|
6
|
+
@simple = simple
|
7
|
+
end
|
8
|
+
|
9
|
+
def parse
|
10
|
+
return if end_of_input?
|
11
|
+
|
12
|
+
previous_cursor = cursor
|
13
|
+
|
14
|
+
if !simple? && match(AMPERSAND) && !next?(SPECIAL)
|
15
|
+
kind = :block
|
16
|
+
elsif !simple && match(ASTERISK + ASTERISK) && !next?(SPECIAL)
|
17
|
+
kind = :keyword
|
18
|
+
elsif !simple? && match(ASTERISK) && !next?(SPECIAL)
|
19
|
+
kind = :regular
|
20
|
+
elsif !next?(SPECIAL)
|
21
|
+
kind = nil
|
22
|
+
else
|
23
|
+
@cursor = previous_cursor
|
24
|
+
buffer!
|
25
|
+
return
|
26
|
+
end
|
27
|
+
|
28
|
+
buffer!
|
29
|
+
|
30
|
+
consume while !next?(SPECIAL) && !end_of_input?
|
31
|
+
|
32
|
+
match(QUESTION_MARK) || match(EXCLAMATION_POINT) if !simple?
|
33
|
+
|
34
|
+
name = buffer!
|
35
|
+
|
36
|
+
if KEYWORDS.include?(name)
|
37
|
+
@cursor = previous_cursor
|
38
|
+
buffer!
|
39
|
+
return
|
40
|
+
else
|
41
|
+
{ name: name, kind: kind }.compact
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
attr_reader :simple
|
48
|
+
|
49
|
+
def simple?
|
50
|
+
!!simple
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
class Code
|
2
|
+
class Parser
|
3
|
+
class If < ::Code::Parser
|
4
|
+
def parse
|
5
|
+
if first_operator = match([IF_KEYWORD, UNLESS_KEYWORD])
|
6
|
+
previous_cursor = cursor
|
7
|
+
first_comments = parse_comments
|
8
|
+
first_condition = parse_subclass(::Code::Parser::If)
|
9
|
+
|
10
|
+
if first_condition
|
11
|
+
first_body = parse_code
|
12
|
+
|
13
|
+
others = []
|
14
|
+
|
15
|
+
while (other = parse_else) || (other = parse_elsif)
|
16
|
+
others << other
|
17
|
+
end
|
18
|
+
|
19
|
+
others = nil if others.empty?
|
20
|
+
|
21
|
+
match(END_KEYWORD)
|
22
|
+
|
23
|
+
{
|
24
|
+
if: {
|
25
|
+
first_operator: first_operator,
|
26
|
+
first_comments: first_comments,
|
27
|
+
first_condition: first_condition,
|
28
|
+
first_body: first_body,
|
29
|
+
others: others
|
30
|
+
}.compact
|
31
|
+
}
|
32
|
+
else
|
33
|
+
@cursor = previous_cursor
|
34
|
+
buffer!
|
35
|
+
parse_subclass(::Code::Parser::IfModifier)
|
36
|
+
end
|
37
|
+
else
|
38
|
+
parse_subclass(::Code::Parser::IfModifier)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def parse_else
|
45
|
+
return unless match(ELSE_KEYWORD)
|
46
|
+
comments_before = parse_comments
|
47
|
+
|
48
|
+
operator = match([IF_KEYWORD, UNLESS_KEYWORD]) || ELSE_KEYWORD
|
49
|
+
|
50
|
+
comments_after = parse_comments
|
51
|
+
|
52
|
+
condition = parse_subclass(::Code::Parser::If)
|
53
|
+
|
54
|
+
body = parse_code
|
55
|
+
|
56
|
+
{
|
57
|
+
operator: operator,
|
58
|
+
comments_before: comments_before,
|
59
|
+
comments_after: comments_after,
|
60
|
+
condition: condition,
|
61
|
+
body: body
|
62
|
+
}.compact
|
63
|
+
end
|
64
|
+
|
65
|
+
def parse_elsif
|
66
|
+
return unless operator = match([ELSIF_KEYWORD, ELSUNLESS_KEYWORD])
|
67
|
+
|
68
|
+
comments = parse_comments
|
69
|
+
condition = parse_subclass(::Code::Parser::If)
|
70
|
+
body = parse_code
|
71
|
+
|
72
|
+
{
|
73
|
+
operator: operator,
|
74
|
+
comments: comments,
|
75
|
+
condition: condition,
|
76
|
+
body: body
|
77
|
+
}.compact
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class Code
|
2
|
+
class Parser
|
3
|
+
class IfModifier < ::Code::Parser
|
4
|
+
def parse
|
5
|
+
left = parse_subclass(::Code::Parser::OrKeyword)
|
6
|
+
|
7
|
+
previous_cursor = cursor
|
8
|
+
|
9
|
+
comments_before = parse_comments(whitespace: [SPACE])
|
10
|
+
|
11
|
+
if left && (operator = match(IF_KEYWORD)) ||
|
12
|
+
(operator = match(UNLESS_KEYWORD))
|
13
|
+
comments_after = parse_comments
|
14
|
+
right = parse_subclass(::Code::Parser::IfModifier)
|
15
|
+
|
16
|
+
if right
|
17
|
+
{
|
18
|
+
if_modifier: {
|
19
|
+
left: left,
|
20
|
+
right: right,
|
21
|
+
operator: operator,
|
22
|
+
comments_before: comments_before,
|
23
|
+
comments_after: comments_after
|
24
|
+
}.compact
|
25
|
+
}
|
26
|
+
else
|
27
|
+
@cursor = previous_cursor
|
28
|
+
buffer!
|
29
|
+
left
|
30
|
+
end
|
31
|
+
else
|
32
|
+
@cursor = previous_cursor
|
33
|
+
buffer!
|
34
|
+
left
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class Code
|
2
|
+
class Parser
|
3
|
+
class List < ::Code::Parser
|
4
|
+
def parse
|
5
|
+
if match(OPENING_SQUARE_BRACKET)
|
6
|
+
list = []
|
7
|
+
|
8
|
+
list << parse_code
|
9
|
+
list << parse_code while match(COMMA) && !end_of_input?
|
10
|
+
|
11
|
+
match(CLOSING_SQUARE_BRACKET)
|
12
|
+
|
13
|
+
{ list: list.reject(&:empty?) }
|
14
|
+
else
|
15
|
+
parse_subclass(::Code::Parser::String)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Code
|
2
|
+
class Parser
|
3
|
+
class Negation < ::Code::Parser
|
4
|
+
def parse
|
5
|
+
if operator = match([EXCLAMATION_POINT, TILDE, PLUS])
|
6
|
+
{
|
7
|
+
negation: {
|
8
|
+
operator: operator,
|
9
|
+
statement: parse_subclass(::Code::Parser::Negation)
|
10
|
+
}
|
11
|
+
}
|
12
|
+
else
|
13
|
+
parse_subclass(::Code::Parser::Function)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class Code
|
2
|
+
class Parser
|
3
|
+
class NotKeyword < ::Code::Parser
|
4
|
+
def parse
|
5
|
+
previous_cursor = cursor
|
6
|
+
|
7
|
+
if match(NOT_KEYWORD)
|
8
|
+
comments = parse_comments
|
9
|
+
right = parse_subclass(::Code::Parser::NotKeyword)
|
10
|
+
|
11
|
+
if right
|
12
|
+
{ not: { right: right, comments: comments }.compact }
|
13
|
+
else
|
14
|
+
@cursor = previous_cursor
|
15
|
+
buffer!
|
16
|
+
parse_subclass(::Code::Parser::Equal)
|
17
|
+
end
|
18
|
+
else
|
19
|
+
parse_subclass(::Code::Parser::Equal)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class Code
|
2
|
+
class Parser
|
3
|
+
class Number < ::Code::Parser
|
4
|
+
def parse
|
5
|
+
if match(DIGITS)
|
6
|
+
if match(X)
|
7
|
+
parse_base(16)
|
8
|
+
elsif match(O)
|
9
|
+
parse_base(8)
|
10
|
+
elsif match(B)
|
11
|
+
parse_base(2)
|
12
|
+
else
|
13
|
+
consume while (next?(DIGITS) || next?(UNDERSCORE)) && !end_of_input?
|
14
|
+
|
15
|
+
if next?(DOT) && next_next?(DIGITS)
|
16
|
+
consume
|
17
|
+
while (next?(DIGITS) || next?(UNDERSCORE)) && !end_of_input?
|
18
|
+
consume
|
19
|
+
end
|
20
|
+
|
21
|
+
{ decimal: buffer.gsub(UNDERSCORE, EMPTY_STRING) }
|
22
|
+
else
|
23
|
+
{ integer: buffer.gsub(UNDERSCORE, EMPTY_STRING).to_i }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
else
|
27
|
+
parse_subclass(::Code::Parser::Boolean)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def parse_base(base)
|
32
|
+
buffer!
|
33
|
+
consume while (next?(DIGITS) || next?(UNDERSCORE)) && !end_of_input?
|
34
|
+
|
35
|
+
{ integer: buffer.gsub(UNDERSCORE, EMPTY_STRING).to_i(base) }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
class Code
|
2
|
+
class Parser
|
3
|
+
class Operation < ::Code::Parser
|
4
|
+
def initialize(input, operators:, subclass:, **kargs)
|
5
|
+
super(input, **kargs)
|
6
|
+
|
7
|
+
@operators = operators
|
8
|
+
@subclass = subclass
|
9
|
+
end
|
10
|
+
|
11
|
+
def parse
|
12
|
+
previous_cursor = cursor
|
13
|
+
left = parse_subclass(subclass)
|
14
|
+
right = []
|
15
|
+
previous_cursor = cursor
|
16
|
+
comments = parse_comments
|
17
|
+
|
18
|
+
while operator = match(operators)
|
19
|
+
comments = parse_comments
|
20
|
+
statement = parse_subclass(subclass)
|
21
|
+
right << {
|
22
|
+
comments: comments,
|
23
|
+
statement: statement,
|
24
|
+
operator: operator
|
25
|
+
}.compact
|
26
|
+
end
|
27
|
+
|
28
|
+
if right.empty?
|
29
|
+
@cursor = previous_cursor
|
30
|
+
buffer!
|
31
|
+
left
|
32
|
+
else
|
33
|
+
{
|
34
|
+
operation: { left: left, comments: comments, right: right }.compact
|
35
|
+
}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
attr_reader :operators, :subclass
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Code
|
2
|
+
class Parser
|
3
|
+
class Power < ::Code::Parser
|
4
|
+
def parse
|
5
|
+
previous_cursor = cursor
|
6
|
+
left = parse_subclass(::Code::Parser::Negation)
|
7
|
+
comments_before = parse_comments
|
8
|
+
if match(ASTERISK + ASTERISK)
|
9
|
+
comments_after = parse_comments
|
10
|
+
right = parse_subclass(::Code::Parser::Power)
|
11
|
+
if right
|
12
|
+
{
|
13
|
+
power: {
|
14
|
+
left: left,
|
15
|
+
right: right,
|
16
|
+
comments_before: comments_before,
|
17
|
+
comments_after: comments_after
|
18
|
+
}.compact
|
19
|
+
}
|
20
|
+
else
|
21
|
+
@cursor = previous_cursor
|
22
|
+
buffer!
|
23
|
+
parse_subclass(::Code::Parser::Negation)
|
24
|
+
end
|
25
|
+
else
|
26
|
+
@cursor = previous_cursor
|
27
|
+
buffer!
|
28
|
+
parse_subclass(::Code::Parser::Negation)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|