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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 75b549d03f89ef60a67380c6bb2ffb9f8c29ae367f1d78b1535d085be7ad1735
4
+ data.tar.gz: 7b92207a50f9ace1308eb0344780fc01d1adcc44629cefc7780ee7271ec14f57
5
+ SHA512:
6
+ metadata.gz: 330c5c233c99a1148e0769bf19bc966e5422891d23a58d7663ef57d09381cd0a7d88ed8a338374d1ead99cd54564eb903148bf50680ccf64056df549db127a20
7
+ data.tar.gz: 522ad02a718830b2d23a14855db77f5c463d5348dc953213b151c80cf1bc3e28b0a84b204109db0320700ed22bb41675b8c4023d1aa7f98bc385996a33b74e26
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ tmp/
data/.overcommit.yml ADDED
@@ -0,0 +1,4 @@
1
+ PreCommit:
2
+ Format:
3
+ enabled: true
4
+ command: ["bin/format"]
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rspec"
4
+ gem "syntax_tree"
5
+ gem "profile"
data/Gemfile.lock ADDED
@@ -0,0 +1,32 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.5.0)
5
+ prettier_print (1.0.2)
6
+ profile (0.4.0)
7
+ rspec (3.12.0)
8
+ rspec-core (~> 3.12.0)
9
+ rspec-expectations (~> 3.12.0)
10
+ rspec-mocks (~> 3.12.0)
11
+ rspec-core (3.12.0)
12
+ rspec-support (~> 3.12.0)
13
+ rspec-expectations (3.12.0)
14
+ diff-lcs (>= 1.2.0, < 2.0)
15
+ rspec-support (~> 3.12.0)
16
+ rspec-mocks (3.12.0)
17
+ diff-lcs (>= 1.2.0, < 2.0)
18
+ rspec-support (~> 3.12.0)
19
+ rspec-support (3.12.0)
20
+ syntax_tree (4.3.0)
21
+ prettier_print (>= 1.0.2)
22
+
23
+ PLATFORMS
24
+ arm64-darwin-21
25
+
26
+ DEPENDENCIES
27
+ profile
28
+ rspec
29
+ syntax_tree
30
+
31
+ BUNDLED WITH
32
+ 2.3.22
data/bin/code-parser ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "optparse"
4
+ require_relative "../lib/code-ruby-parser"
5
+ require "json"
6
+
7
+ options = {}
8
+
9
+ OptionParser
10
+ .new do |opts|
11
+ opts.banner = "Usage: bin/code-parser [options]"
12
+
13
+ opts.on(
14
+ "-i INPUT",
15
+ "--input=INPUT",
16
+ "Input in the code language (String or File)"
17
+ ) do |input|
18
+ input = File.read(input) if File.exists?(input)
19
+
20
+ options[:input] = input
21
+ end
22
+ end
23
+ .parse!
24
+
25
+ input = options.fetch(:input, "")
26
+
27
+ puts JSON.pretty_generate(::Code::Parser.parse(input))
data/bin/format ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env fish
2
+
3
+ stree write Gemfile lib/**/*.rb spec/**/*.rb bin/code-parser
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "optparse"
4
+ require_relative "../lib/code-ruby-parser"
5
+ require "json"
6
+
7
+ options = {}
8
+
9
+ OptionParser
10
+ .new do |opts|
11
+ opts.banner = "Usage: bin/template-parser [options]"
12
+
13
+ opts.on(
14
+ "-i INPUT",
15
+ "--input=INPUT",
16
+ "Input in the code language (String or File)"
17
+ ) do |input|
18
+ input = File.read(input) if File.exists?(input)
19
+
20
+ options[:input] = input
21
+ end
22
+ end
23
+ .parse!
24
+
25
+ input = options.fetch(:input, "")
26
+
27
+ puts JSON.pretty_generate(::Template::Parser.parse(input))
data/docs/class.code ADDED
@@ -0,0 +1,9 @@
1
+ class ApiClient
2
+ get = (url) => {
3
+ fetch(url)
4
+ }
5
+ end
6
+
7
+ class Twitter < ApiClient
8
+ self.base_url = "https://api.twitter.com"
9
+ end
data/docs/meetup.code ADDED
@@ -0,0 +1,14 @@
1
+ url = fetch(:url) { "https://www.meetup.com/parisrb" }
2
+ response = HTTP.get(url)
3
+ times = response.css(".groupHome-eventsList-upcomingEvents time")
4
+ times = times.map(&:datetime).map do |time|
5
+ Time.from_epoch(time.to_integer)
6
+ end
7
+
8
+ times.each do |time|
9
+ if (1.day.from_now...(1.day.from_now + 1.hour)).include?(time)
10
+ Sms.send("Event in one day {url}")
11
+ elsif (2.hours.from_now...(1.hour.from_now)).include(time)
12
+ Sms.send("Event in two hours {url}")
13
+ end
14
+ end
data/docs/rain.code ADDED
@@ -0,0 +1,23 @@
1
+ paris = { latitude: 48.8566, longitude: 2.4022 }
2
+ latitude = fetch(:latitude) { paris.latitude }
3
+ longitude = fetch(:longitude) { paris.longitude }
4
+ duration = fetch(:duration) { 1.hour }
5
+ hour = duration.from_now.hour
6
+
7
+ response = HTTP.get(
8
+ "https://api.open-meteo.com/v1/forecast",
9
+ parameters: {
10
+ latitude: latitude,
11
+ longitude: longitude,
12
+ hourly: :precipitation
13
+ }
14
+ )
15
+
16
+ precipitation = response.hourly.precipitation[hour]
17
+ precipitation = (precipitation * 100).to_integer
18
+
19
+ if precipitation > 0
20
+ Sms.send(
21
+ "There will be {precipitation}% of precipitation in the next hour"
22
+ )
23
+ end
data/docs/slack.code ADDED
@@ -0,0 +1,17 @@
1
+ Slack.send("Who is leading the syncs?", channel: "#team-template")
2
+
3
+ Twitter.send("What do you want to do this week?")
4
+
5
+ Discord.send("Who will be the game master this week?")
6
+
7
+ Email.send(
8
+ subject: "What did you do last week?",
9
+ from: "dorian@thoughtbot.com",
10
+ reply_to: "rob@thoughtbot.com"
11
+ )
12
+
13
+ Email.send(
14
+ subject: "What do you want to do this week?",
15
+ from: "dorian@thoughtbot.com",
16
+ reply_to: "rob@thoughtbot.com"
17
+ )
data/docs/stripe.code ADDED
@@ -0,0 +1,7 @@
1
+ event = Stripe::Webhook.event
2
+
3
+ if event.type == "payment_intent.succeeded"
4
+ payment_intent = event.data.object
5
+ amount = Money.format(payment_intent.amount, payment_intent.currency)
6
+ Sms.send("You got paid {amount}")
7
+ end
data/docs/twitter.code ADDED
@@ -0,0 +1,7 @@
1
+ twitter_username = fetch(:twitter_username) { "dorianmariefr" }
2
+
3
+ Twitter.search("to:{twitter_username}", type: :recent).each do |tweet|
4
+ next if Storage.exists?(tweet.id)
5
+ Storage.create!(tweet.id)
6
+ Sms.send("New mention: {tweet.user.screen_name}: {tweet.text}")
7
+ end
@@ -0,0 +1,13 @@
1
+ class Code
2
+ class Parser
3
+ class Addition < ::Code::Parser
4
+ def parse
5
+ parse_subclass(
6
+ ::Code::Parser::Operation,
7
+ operators: [PLUS, MINUS],
8
+ subclass: ::Code::Parser::Multiplication
9
+ )
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ class Code
2
+ class Parser
3
+ class AndOperator < ::Code::Parser
4
+ def parse
5
+ parse_subclass(
6
+ ::Code::Parser::Operation,
7
+ operators: [AMPERSAND + AMPERSAND],
8
+ subclass: ::Code::Parser::GreaterThan
9
+ )
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ class Code
2
+ class Parser
3
+ class BitwiseAnd < ::Code::Parser
4
+ def parse
5
+ parse_subclass(
6
+ ::Code::Parser::Operation,
7
+ operators: [AMPERSAND],
8
+ subclass: ::Code::Parser::Shift
9
+ )
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ class Code
2
+ class Parser
3
+ class BitwiseOr < ::Code::Parser
4
+ def parse
5
+ parse_subclass(
6
+ ::Code::Parser::Operation,
7
+ operators: [PIPE, CARET],
8
+ subclass: ::Code::Parser::BitwiseAnd
9
+ )
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ class Code
2
+ class Parser
3
+ class Boolean < ::Code::Parser
4
+ def parse
5
+ if match(BOOLEAN_KEYWORDS)
6
+ { boolean: buffer }
7
+ else
8
+ parse_subclass(::Code::Parser::Nothing)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,174 @@
1
+ class Code
2
+ class Parser
3
+ class Call < ::Code::Parser
4
+ def parse
5
+ identifier = parse_subclass(::Code::Parser::Identifier)
6
+ return unless identifier
7
+
8
+ if match(OPENING_PARENTHESIS)
9
+ arguments = []
10
+
11
+ arguments << (parse_keyword_argument || parse_regular_argument)
12
+
13
+ while match(COMMA) && !end_of_input?
14
+ arguments << (parse_keyword_argument || parse_regular_argument)
15
+ end
16
+
17
+ arguments.compact!
18
+
19
+ match(CLOSING_PARENTHESIS)
20
+ else
21
+ arguments = nil
22
+ end
23
+
24
+ previous_cursor = cursor
25
+ comments = parse_comments
26
+
27
+ if match(DO_KEYWORD)
28
+ block = parse_block
29
+ match(END_KEYWORD)
30
+ elsif match(OPENING_CURLY_BRACKET)
31
+ block = parse_block
32
+ match(CLOSING_CURLY_BRACKET)
33
+ else
34
+ @cursor = previous_cursor
35
+ buffer!
36
+ block = nil
37
+ end
38
+
39
+ {
40
+ call: {
41
+ **identifier,
42
+ arguments: arguments,
43
+ block: block,
44
+ comments: comments
45
+ }.compact
46
+ }
47
+ end
48
+
49
+ private
50
+
51
+ def parse_block
52
+ comments = parse_comments
53
+
54
+ if match(PIPE)
55
+ parameters = []
56
+
57
+ parameters << (parse_keyword_parameter || parse_regular_parameter)
58
+
59
+ while match(COMMA) && !end_of_input?
60
+ parameters << (parse_keyword_parameter || parse_regular_parameter)
61
+ end
62
+
63
+ match(PIPE)
64
+
65
+ {
66
+ comments: comments,
67
+ parameters: parameters.compact,
68
+ body: parse_code
69
+ }.compact
70
+ else
71
+ { comments: comments, body: parse_code }.compact
72
+ end
73
+ end
74
+
75
+ def parse_keyword_argument
76
+ previous_cursor = cursor
77
+
78
+ comments_before = parse_comments
79
+ key = parse_subclass(::Code::Parser::Statement)
80
+ comments_after = parse_comments
81
+
82
+ if key && match(COLON) || match(EQUAL + GREATER)
83
+ default = parse_code
84
+ default = nil if default.empty?
85
+ {
86
+ comments_before: comments_before,
87
+ comments_after: comments_after,
88
+ default: default,
89
+ keyword: true,
90
+ statement: key
91
+ }.compact
92
+ else
93
+ @cursor = previous_cursor
94
+ buffer!
95
+ return
96
+ end
97
+ end
98
+
99
+ def parse_regular_argument
100
+ code = parse_code
101
+ return if code.empty?
102
+ code
103
+ end
104
+
105
+ def parse_keyword_parameter
106
+ previous_cursor = cursor
107
+
108
+ comments_before = parse_comments
109
+ key = parse_subclass(::Code::Parser::Identifier)
110
+ comments_after = parse_comments
111
+
112
+ if key && match(COLON) || match(EQUAL + GREATER)
113
+ default = parse_default
114
+
115
+ {
116
+ comments_before: comments_before,
117
+ comments_after: comments_after,
118
+ default: default,
119
+ keyword: true,
120
+ **key
121
+ }.compact
122
+ else
123
+ @cursor = previous_cursor
124
+ buffer!
125
+ return
126
+ end
127
+ end
128
+
129
+ def parse_regular_parameter
130
+ previous_cursor = cursor
131
+ comments_before = parse_comments
132
+ identifier = parse_subclass(::Code::Parser::Identifier)
133
+ if identifier
134
+ comments_after = parse_comments
135
+
136
+ if match(EQUAL)
137
+ default = parse_default
138
+
139
+ {
140
+ comments_before: comments_before,
141
+ comments_after: comments_after,
142
+ default: default,
143
+ **identifier
144
+ }.compact
145
+ else
146
+ {
147
+ comments_before: comments_before,
148
+ comments_after: comments_after,
149
+ **identifier
150
+ }.compact
151
+ end
152
+ else
153
+ @cursor = previous_cursor
154
+ buffer!
155
+ return
156
+ end
157
+ end
158
+
159
+ def parse_default
160
+ comments_before = parse_comments
161
+ statement = parse_subclass(::Code::Parser::BitwiseAnd)
162
+ comments_after = parse_comments
163
+
164
+ default = {
165
+ comments_before: comments_before,
166
+ statement: statement,
167
+ comments_after: comments_after
168
+ }.compact
169
+
170
+ default.empty? ? nil : default
171
+ end
172
+ end
173
+ end
174
+ end
@@ -0,0 +1,41 @@
1
+ class Code
2
+ class Parser
3
+ class ChainedCall < ::Code::Parser
4
+ def parse
5
+ previous_cursor = cursor
6
+ left = parse_dictionnary
7
+ comments_before = parse_comments
8
+
9
+ if left && match([DOT, COLON + COLON])
10
+ comments_after = parse_comments
11
+ right = parse_dictionnary
12
+ if right
13
+ chained_call = [{ left: left, right: right }]
14
+ while match([DOT, COLON + COLON]) && other_right = parse_dictionnary
15
+ chained_call << { right: other_right }
16
+ end
17
+ {
18
+ chained_call: {
19
+ calls: chained_call,
20
+ comments_before: comments_before,
21
+ comments_after: comments_after
22
+ }.compact
23
+ }
24
+ else
25
+ @cursor = previous_cursor
26
+ buffer!
27
+ parse_dictionnary
28
+ end
29
+ else
30
+ @cursor = previous_cursor
31
+ buffer!
32
+ parse_dictionnary
33
+ end
34
+ end
35
+
36
+ def parse_dictionnary
37
+ parse_subclass(::Code::Parser::Dictionnary)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,56 @@
1
+ class Code
2
+ class Parser
3
+ class Class < ::Code::Parser
4
+ def parse
5
+ previous_cursor = cursor
6
+
7
+ if match(CLASS_KEYWORD)
8
+ first_comments = parse_comments
9
+
10
+ name = parse_subclass(::Code::Parser::Identifier, simple: true)
11
+
12
+ if name
13
+ second_comments = parse_comments
14
+
15
+ if match(LESSER)
16
+ previous_cursor = cursor
17
+ third_comments = parse_comments
18
+ superclass =
19
+ parse_subclass(::Code::Parser::Identifier, simple: true)
20
+
21
+ if !superclass
22
+ @cursor = previous_cursor
23
+ buffer!
24
+ third_comments = nil
25
+ end
26
+ else
27
+ third_comments = nil
28
+ superclass = nil
29
+ end
30
+
31
+ body = parse_code
32
+
33
+ match(END_KEYWORD)
34
+
35
+ {
36
+ class: {
37
+ name: name,
38
+ superclass: superclass,
39
+ first_comments: first_comments,
40
+ second_comments: second_comments,
41
+ third_comments: third_comments,
42
+ body: body
43
+ }.compact
44
+ }
45
+ else
46
+ @cursor = previous_cursor
47
+ buffer!
48
+ parse_subclass(::Code::Parser::While)
49
+ end
50
+ else
51
+ parse_subclass(::Code::Parser::While)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,20 @@
1
+ class Code
2
+ class Parser
3
+ class Code < ::Code::Parser
4
+ def parse
5
+ output = []
6
+
7
+ comments = parse_comments
8
+ output << { comments: comments } if comments
9
+
10
+ while code = parse_subclass(::Code::Parser::Statement)
11
+ output << code
12
+ comments = parse_comments
13
+ output << { comments: comments } if comments
14
+ end
15
+
16
+ output
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,46 @@
1
+ class Code
2
+ class Parser
3
+ class Comments < ::Code::Parser
4
+ def initialize(input, whitespace: WHITESPACE, **kargs)
5
+ super(input, **kargs)
6
+ @whitespace = whitespace
7
+ @has_line_comments = whitespace.include?(NEWLINE)
8
+ end
9
+
10
+ def parse
11
+ comments = []
12
+
13
+ while next?(whitespace) || next?(SLASH + ASTERISK) ||
14
+ (line_comments? && (next?(SLASH + SLASH) || next?(HASH)))
15
+ consume while next?(whitespace)
16
+ buffer!
17
+
18
+ if match(SLASH + SLASH) || match(HASH)
19
+ consume while !next?(NEWLINE) && !end_of_input?
20
+ match(NEWLINE)
21
+ comments << buffer
22
+ end
23
+
24
+ consume while next?(whitespace)
25
+ buffer!
26
+
27
+ if match(SLASH + ASTERISK)
28
+ consume while !next?(ASTERISK + SLASH) && !end_of_input?
29
+ match(ASTERISK + SLASH)
30
+ comments << buffer
31
+ end
32
+ end
33
+
34
+ comments.empty? ? nil : comments
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ attr_reader :whitespace, :has_line_comments
41
+
42
+ def line_comments?
43
+ !!has_line_comments
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,48 @@
1
+ class Code
2
+ class Parser
3
+ class Dictionnary < ::Code::Parser
4
+ def parse
5
+ if match(OPENING_CURLY_BRACKET)
6
+ dictionnary = []
7
+
8
+ comments = parse_comments
9
+
10
+ dictionnary << parse_key_value
11
+
12
+ dictionnary << parse_key_value while match(COMMA) && !end_of_input?
13
+
14
+ match(CLOSING_CURLY_BRACKET)
15
+
16
+ { dictionnary: dictionnary.compact, comments: comments }
17
+ else
18
+ parse_subclass(::Code::Parser::List)
19
+ end
20
+ end
21
+
22
+ def parse_key_value
23
+ comments_before = parse_comments
24
+
25
+ key = parse_subclass(::Code::Parser::Statement)
26
+
27
+ comments_after = parse_comments
28
+
29
+ return unless key
30
+
31
+ if match(COLON) || match(EQUAL + GREATER)
32
+ {
33
+ key: key,
34
+ value: parse_code,
35
+ comments_before: comments_before,
36
+ comments_after: comments_after
37
+ }.compact
38
+ else
39
+ {
40
+ key: key,
41
+ comments_before: comments_before,
42
+ comments_after: comments_after
43
+ }.compact
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end