code-ruby-parser 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.overcommit.yml +4 -0
  4. data/Gemfile +5 -0
  5. data/Gemfile.lock +32 -0
  6. data/bin/code-parser +27 -0
  7. data/bin/format +3 -0
  8. data/bin/template-parser +27 -0
  9. data/docs/class.code +9 -0
  10. data/docs/meetup.code +14 -0
  11. data/docs/rain.code +23 -0
  12. data/docs/slack.code +17 -0
  13. data/docs/stripe.code +7 -0
  14. data/docs/twitter.code +7 -0
  15. data/lib/code/parser/addition.rb +13 -0
  16. data/lib/code/parser/and_operator.rb +13 -0
  17. data/lib/code/parser/bitwise_and.rb +13 -0
  18. data/lib/code/parser/bitwise_or.rb +13 -0
  19. data/lib/code/parser/boolean.rb +13 -0
  20. data/lib/code/parser/call.rb +174 -0
  21. data/lib/code/parser/chained_call.rb +41 -0
  22. data/lib/code/parser/class.rb +56 -0
  23. data/lib/code/parser/code.rb +20 -0
  24. data/lib/code/parser/comments.rb +46 -0
  25. data/lib/code/parser/dictionnary.rb +48 -0
  26. data/lib/code/parser/equal.rb +39 -0
  27. data/lib/code/parser/equality.rb +20 -0
  28. data/lib/code/parser/error/syntax_error.rb +36 -0
  29. data/lib/code/parser/error.rb +6 -0
  30. data/lib/code/parser/function.rb +109 -0
  31. data/lib/code/parser/greater_than.rb +13 -0
  32. data/lib/code/parser/group.rb +15 -0
  33. data/lib/code/parser/identifier.rb +54 -0
  34. data/lib/code/parser/if.rb +81 -0
  35. data/lib/code/parser/if_modifier.rb +39 -0
  36. data/lib/code/parser/list.rb +20 -0
  37. data/lib/code/parser/multiplication.rb +13 -0
  38. data/lib/code/parser/negation.rb +18 -0
  39. data/lib/code/parser/not_keyword.rb +24 -0
  40. data/lib/code/parser/nothing.rb +13 -0
  41. data/lib/code/parser/number.rb +39 -0
  42. data/lib/code/parser/operation.rb +44 -0
  43. data/lib/code/parser/or_keyword.rb +13 -0
  44. data/lib/code/parser/or_operator.rb +13 -0
  45. data/lib/code/parser/power.rb +33 -0
  46. data/lib/code/parser/range.rb +13 -0
  47. data/lib/code/parser/rescue.rb +38 -0
  48. data/lib/code/parser/shift.rb +13 -0
  49. data/lib/code/parser/statement.rb +9 -0
  50. data/lib/code/parser/string.rb +61 -0
  51. data/lib/code/parser/ternary.rb +73 -0
  52. data/lib/code/parser/unary_minus.rb +23 -0
  53. data/lib/code/parser/while.rb +36 -0
  54. data/lib/code/parser.rb +237 -0
  55. data/lib/code-ruby-parser.rb +7 -0
  56. data/lib/code.rb +2 -0
  57. data/lib/template/parser.rb +32 -0
  58. data/lib/template-ruby-parser.rb +7 -0
  59. data/lib/template.rb +2 -0
  60. data/spec/code/parser/addition_spec.rb +26 -0
  61. data/spec/code/parser/and_operator_spec.rb +26 -0
  62. data/spec/code/parser/bitwise_and_spec.rb +26 -0
  63. data/spec/code/parser/bitwise_or_spec.rb +26 -0
  64. data/spec/code/parser/boolean_spec.rb +13 -0
  65. data/spec/code/parser/call_spec.rb +52 -0
  66. data/spec/code/parser/chained_call_spec.rb +33 -0
  67. data/spec/code/parser/class_spec.rb +32 -0
  68. data/spec/code/parser/code_spec.rb +13 -0
  69. data/spec/code/parser/dictionnary_spec.rb +40 -0
  70. data/spec/code/parser/equal_spec.rb +42 -0
  71. data/spec/code/parser/equality_spec.rb +26 -0
  72. data/spec/code/parser/function_spec.rb +43 -0
  73. data/spec/code/parser/greater_than_spec.rb +26 -0
  74. data/spec/code/parser/group_spec.rb +13 -0
  75. data/spec/code/parser/if_modifier_spec.rb +26 -0
  76. data/spec/code/parser/if_spec.rb +39 -0
  77. data/spec/code/parser/list_spec.rb +27 -0
  78. data/spec/code/parser/multiplication_spec.rb +26 -0
  79. data/spec/code/parser/negation_spec.rb +13 -0
  80. data/spec/code/parser/not_keyword_spec.rb +21 -0
  81. data/spec/code/parser/nothing_spec.rb +20 -0
  82. data/spec/code/parser/number_spec.rb +24 -0
  83. data/spec/code/parser/or_keyword_spec.rb +26 -0
  84. data/spec/code/parser/or_operator_spec.rb +26 -0
  85. data/spec/code/parser/power_spec.rb +21 -0
  86. data/spec/code/parser/range_spec.rb +21 -0
  87. data/spec/code/parser/rescue_spec.rb +26 -0
  88. data/spec/code/parser/shift_spec.rb +26 -0
  89. data/spec/code/parser/string_spec.rb +27 -0
  90. data/spec/code/parser/ternary_spec.rb +26 -0
  91. data/spec/code/parser/unary_minus_spec.rb +21 -0
  92. data/spec/code/parser/while_spec.rb +32 -0
  93. data/spec/spec_helper.rb +6 -0
  94. data/spec/template/parser_spec.rb +13 -0
  95. data/template-ruby-parser.gemspec +16 -0
  96. 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,6 @@
1
+ class Code
2
+ class Parser
3
+ class Error < ::StandardError
4
+ end
5
+ end
6
+ 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,13 @@
1
+ class Code
2
+ class Parser
3
+ class Multiplication < ::Code::Parser
4
+ def parse
5
+ parse_subclass(
6
+ ::Code::Parser::Operation,
7
+ operators: [ASTERISK, SLASH, PERCENT],
8
+ subclass: ::Code::Parser::UnaryMinus
9
+ )
10
+ end
11
+ end
12
+ end
13
+ 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,13 @@
1
+ class Code
2
+ class Parser
3
+ class Nothing < ::Code::Parser
4
+ def parse
5
+ if match(NOTHING_KEYWORDS)
6
+ { nothing: buffer }
7
+ else
8
+ parse_subclass(::Code::Parser::Group)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ 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,13 @@
1
+ class Code
2
+ class Parser
3
+ class OrKeyword < ::Code::Parser
4
+ def parse
5
+ parse_subclass(
6
+ ::Code::Parser::Operation,
7
+ operators: [AND_KEYWORD, OR_KEYWORD],
8
+ subclass: ::Code::Parser::NotKeyword
9
+ )
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ class Code
2
+ class Parser
3
+ class OrOperator < ::Code::Parser
4
+ def parse
5
+ parse_subclass(
6
+ ::Code::Parser::Operation,
7
+ operators: [PIPE + PIPE],
8
+ subclass: ::Code::Parser::GreaterThan
9
+ )
10
+ end
11
+ end
12
+ end
13
+ 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
@@ -0,0 +1,13 @@
1
+ class Code
2
+ class Parser
3
+ class Range < ::Code::Parser
4
+ def parse
5
+ parse_subclass(
6
+ ::Code::Parser::Operation,
7
+ operators: [DOT + DOT + DOT, DOT + DOT],
8
+ subclass: ::Code::Parser::OrOperator
9
+ )
10
+ end
11
+ end
12
+ end
13
+ end