language-ruby 0.6.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bdf5e247df3ee0c287a560265c60107d161eb4b7cb71610f6f50c15c81c2e3aa
4
- data.tar.gz: acfe4eea02eb399831fd378adb0bd69100efbdecaeead3c99a2faaec11e552cb
3
+ metadata.gz: fe75dad140254848b0688e73fc0361003867abf259e3efd57eb8709072808461
4
+ data.tar.gz: 592c2cf305d38613461981802bb63a9288b2a7bac862220cb818c4e1b9e1922c
5
5
  SHA512:
6
- metadata.gz: 318d1dd9888a5aee6aec7fef5410b9092f169e6e12e1d4a0608c6a2e36b2ae4b3bfc6412052a8e331a9b1260bf4387ccfa6340e1ea74f7511da049ff222d4050
7
- data.tar.gz: 5c0c443194c047a08c461f9b713fcf131ebd12ce479b81d344415202694106a7db00e19547c37319c6d69d4a0bc78a768b0a8aaf1d29e1b9a7ae1369d87c520e
6
+ metadata.gz: b61958d200d6d2e2f1a0ed41e93a992320e3b224c8e65f0cfb3e3ff35ad78f07b930234d2ec190cad4384b1127a347d7651597831033bf1b14bda18a488f6f41
7
+ data.tar.gz: eb44f9c8522a461b4b40e7b369a9ac0653ff30c710c2c5395840e3e5b8181596ce4553fa7033370636e6974dd79e2e326e0e7bf6d0f2061be84468d30b670b49
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ *.gem
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.3.0
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 3.3.0
data/Gemfile CHANGED
@@ -1,5 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source "https://rubygems.org"
2
4
 
3
5
  gemspec
4
6
 
7
+ ruby "3.3.0"
8
+
5
9
  gem "rspec"
data/Gemfile.lock ADDED
@@ -0,0 +1,38 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ language-ruby (0.6.0)
5
+ zeitwerk (~> 2)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ diff-lcs (1.5.0)
11
+ rspec (3.12.0)
12
+ rspec-core (~> 3.12.0)
13
+ rspec-expectations (~> 3.12.0)
14
+ rspec-mocks (~> 3.12.0)
15
+ rspec-core (3.12.2)
16
+ rspec-support (~> 3.12.0)
17
+ rspec-expectations (3.12.3)
18
+ diff-lcs (>= 1.2.0, < 2.0)
19
+ rspec-support (~> 3.12.0)
20
+ rspec-mocks (3.12.6)
21
+ diff-lcs (>= 1.2.0, < 2.0)
22
+ rspec-support (~> 3.12.0)
23
+ rspec-support (3.12.1)
24
+ zeitwerk (2.6.12)
25
+
26
+ PLATFORMS
27
+ arm64-darwin-22
28
+ arm64-darwin-23
29
+
30
+ DEPENDENCIES
31
+ language-ruby!
32
+ rspec
33
+
34
+ RUBY VERSION
35
+ ruby 3.3.0p0
36
+
37
+ BUNDLED WITH
38
+ 2.4.21
data/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # language-ruby
2
+
3
+ A Parsing Expression Grammar (PEG) for making parsers
@@ -1,3 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "English"
1
4
  require_relative "lib/language/version"
2
5
 
3
6
  Gem::Specification.new do |s|
@@ -7,8 +10,7 @@ Gem::Specification.new do |s|
7
10
  s.description = s.summary
8
11
  s.authors = ["Dorian Marié"]
9
12
  s.email = "dorian@dorianmarie.fr"
10
- s.files = `git ls-files`.split($/)
11
- s.test_files = s.files.grep(%r{^(test|spec|features)/})
13
+ s.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
12
14
  s.require_paths = ["lib"]
13
15
  s.homepage = "https://github.com/dorianmariefr/language-ruby"
14
16
  s.license = "MIT"
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Language
4
+ class Atom
5
+ class Absent < Atom
6
+ def initialize(parent: nil)
7
+ @parent = parent
8
+ end
9
+
10
+ def parse(parser)
11
+ clone =
12
+ Parser.new(
13
+ root: self,
14
+ input: parser.input,
15
+ cursor: parser.cursor,
16
+ buffer: parser.buffer
17
+ )
18
+ @parent&.parse(clone)
19
+ rescue Parser::Interuption
20
+ else
21
+ raise Parser::Interuption.new(parser, self)
22
+ end
23
+
24
+ def to_s
25
+ @parent ? "(#{@parent}).absent" : "absent"
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Language
4
+ class Atom
5
+ class Aka < Atom
6
+ def initialize(name:, parent:)
7
+ @name = name
8
+ @parent = parent
9
+ end
10
+
11
+ def parse(parser)
12
+ clone =
13
+ Parser.new(root: self, input: parser.input, cursor: parser.cursor)
14
+
15
+ @parent.parse(clone)
16
+
17
+ if clone.output?
18
+ parser.output = Output.new(@name => clone.output)
19
+ else
20
+ parser.output[@name] = Output.new(clone.buffer)
21
+ parser.buffer = ""
22
+ end
23
+
24
+ parser.cursor = clone.cursor
25
+ end
26
+
27
+ def to_s
28
+ @parent ? "#{@parent}.aka(#{@name.inspect})" : "aka(#{@name.inspect})"
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Language
4
+ class Atom
5
+ class And < Atom
6
+ def initialize(left:, right:)
7
+ @left = left
8
+ @right = right
9
+ end
10
+
11
+ def parse(parser)
12
+ @left.parse(parser)
13
+ right_clone =
14
+ Parser.new(
15
+ root: self,
16
+ input: parser.input,
17
+ cursor: parser.cursor,
18
+ buffer: parser.buffer
19
+ )
20
+ @right.parse(right_clone)
21
+ parser.cursor = right_clone.cursor
22
+ parser.buffer = right_clone.buffer
23
+
24
+ parser.output.merge(right_clone.output)
25
+ end
26
+
27
+ def to_s
28
+ "#{@left} >> #{@right}".to_s
29
+ end
30
+ end
31
+ end
32
+ end
@@ -3,6 +3,13 @@
3
3
  class Language
4
4
  class Atom
5
5
  class Any < Atom
6
+ def parse(parser)
7
+ parser.consume(1)
8
+ end
9
+
10
+ def to_s
11
+ "any"
12
+ end
6
13
  end
7
14
  end
8
15
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Language
4
+ class Atom
5
+ class Ignore < Atom
6
+ def initialize(parent:)
7
+ @parent = parent
8
+ end
9
+
10
+ def parse(parser)
11
+ clone =
12
+ Parser.new(
13
+ root: self,
14
+ input: parser.input,
15
+ cursor: parser.cursor,
16
+ buffer: parser.buffer
17
+ )
18
+ @parent.parse(clone)
19
+ parser.cursor = clone.cursor
20
+ end
21
+
22
+ def to_s
23
+ "#{@parent}.ignore"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Language
4
+ class Atom
5
+ class Maybe < Atom
6
+ def initialize(parent:)
7
+ @parent = parent
8
+ end
9
+
10
+ def parse(parser)
11
+ clone =
12
+ Parser.new(
13
+ root: self,
14
+ input: parser.input,
15
+ cursor: parser.cursor,
16
+ buffer: parser.buffer
17
+ )
18
+
19
+ @parent.parse(clone)
20
+ rescue Parser::Interuption
21
+ else
22
+ parser.buffer = clone.buffer
23
+ parser.cursor = clone.cursor
24
+ parser.output = clone.output
25
+ end
26
+
27
+ def to_s
28
+ @parent ? "#{@parent}.maybe" : "maybe"
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Language
4
+ class Atom
5
+ class Or < Atom
6
+ def initialize(left:, right:)
7
+ @left = left
8
+ @right = right
9
+ end
10
+
11
+ def parse(parser)
12
+ left_clone =
13
+ Parser.new(
14
+ root: self,
15
+ input: parser.input,
16
+ cursor: parser.cursor,
17
+ buffer: parser.buffer
18
+ )
19
+
20
+ right_clone =
21
+ Parser.new(
22
+ root: self,
23
+ input: parser.input,
24
+ cursor: parser.cursor,
25
+ buffer: parser.buffer
26
+ )
27
+
28
+ begin
29
+ @left.parse(left_clone)
30
+ parser.cursor = left_clone.cursor
31
+ parser.buffer = left_clone.buffer
32
+ parser.output.merge(left_clone.output)
33
+ rescue Parser::Interuption
34
+ @right.parse(right_clone)
35
+ parser.cursor = right_clone.cursor
36
+ parser.buffer = right_clone.buffer
37
+ parser.output.merge(right_clone.output)
38
+ end
39
+ end
40
+
41
+ def to_s
42
+ "((#{@left}) | (#{@right}))"
43
+ end
44
+ end
45
+ end
46
+ end
@@ -3,13 +3,55 @@
3
3
  class Language
4
4
  class Atom
5
5
  class Repeat < Atom
6
- def initialize(parent:)
6
+ def initialize(parent: nil, minimum: 0, maximum: nil)
7
7
  @parent = parent
8
+ @minimum = minimum
9
+ @maximum = maximum
10
+ end
11
+
12
+ def parse(parser)
13
+ return unless @parent
14
+
15
+ @minimum.times { match(parser) }
16
+ if @maximum.nil?
17
+ begin
18
+ loop { match(parser) }
19
+ rescue Parser::Interuption
20
+ end
21
+ else
22
+ begin
23
+ (@maximum - @minimum).times { match(parser) }
24
+ rescue Parser::Interuption
25
+ end
26
+ end
27
+ end
28
+
29
+ def to_s
30
+ minimum = @minimum.zero? ? "" : @minimum.to_s
31
+ maximum = @maximum.nil? ? "" : ", #{@maximum}"
32
+ parenthesis =
33
+ (minimum.empty? && maximum.empty?) ? "" : "(#{minimum}#{maximum})"
34
+
35
+ @parent ? "(#{@parent}).repeat#{parenthesis}" : "repeat#{parenthesis}"
8
36
  end
9
37
 
10
38
  private
11
39
 
12
- attr_reader :parent
40
+ def match(parser)
41
+ clone =
42
+ Parser.new(
43
+ root: self,
44
+ input: parser.input,
45
+ cursor: parser.cursor,
46
+ buffer: parser.buffer
47
+ )
48
+
49
+ @parent.parse(clone)
50
+
51
+ parser.cursor = clone.cursor
52
+ parser.buffer = clone.buffer
53
+ parser.output << clone.output
54
+ end
13
55
  end
14
56
  end
15
57
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Language
4
+ class Atom
5
+ class Str < Atom
6
+ def initialize(string:)
7
+ @string = string
8
+ end
9
+
10
+ def parse(parser)
11
+ raise Parser::Str::NotFound.new(parser, @string) unless parser.next?(@string)
12
+
13
+ parser.consume(@string.size)
14
+ end
15
+
16
+ def to_s
17
+ "str(#{@string.inspect})"
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Language
4
+ class Atom
5
+ class Then < Atom
6
+ def initialize(parent:, block:)
7
+ @parent = parent
8
+ @block = block
9
+ end
10
+
11
+ def parse(parser)
12
+ @parent.parse(parser)
13
+ parser.output = Output.from_raw(@block.call(parser.output.to_raw))
14
+ end
15
+
16
+ def to_s
17
+ "(#{@parent}).then {}"
18
+ end
19
+ end
20
+ end
21
+ end
data/lib/language/atom.rb CHANGED
@@ -2,270 +2,6 @@
2
2
 
3
3
  class Language
4
4
  class Atom
5
- class Any < Atom
6
- def parse(parser)
7
- parser.consume(1)
8
- end
9
-
10
- def to_s
11
- "any"
12
- end
13
- end
14
-
15
- class Then < Atom
16
- def initialize(parent:, block:)
17
- @parent = parent
18
- @block = block
19
- end
20
-
21
- def parse(parser)
22
- @parent.parse(parser)
23
- parser.output = Output.from_raw(@block.call(parser.output.to_raw))
24
- end
25
-
26
- def to_s
27
- "(#{@parent}).then {}"
28
- end
29
- end
30
-
31
- class Repeat < Atom
32
- def initialize(parent: nil, minimum: 0, maximum: nil)
33
- @parent = parent
34
- @minimum = minimum
35
- @maximum = maximum
36
- end
37
-
38
- def parse(parser)
39
- return unless @parent
40
-
41
- @minimum.times { match(parser) }
42
- if @maximum.nil?
43
- begin
44
- loop { match(parser) }
45
- rescue Parser::Interuption
46
- end
47
- else
48
- begin
49
- (@maximum - @minimum).times { match(parser) }
50
- rescue Parser::Interuption
51
- end
52
- end
53
- end
54
-
55
- def to_s
56
- minimum = @minimum.zero? ? "" : @minimum.to_s
57
- maximum = @maximum.nil? ? "" : ", #{@maximum}"
58
- parenthesis =
59
- minimum.empty? && maximum.empty? ? "" : "(#{minimum}#{maximum})"
60
-
61
- @parent ? "(#{@parent}).repeat#{parenthesis}" : "repeat#{parenthesis}"
62
- end
63
-
64
- private
65
-
66
- def match(parser)
67
- clone =
68
- Parser.new(
69
- root: self,
70
- input: parser.input,
71
- cursor: parser.cursor,
72
- buffer: parser.buffer
73
- )
74
-
75
- @parent.parse(clone)
76
-
77
- parser.cursor = clone.cursor
78
- parser.buffer = clone.buffer
79
- parser.output << clone.output
80
- end
81
- end
82
-
83
- class Str < Atom
84
- def initialize(string:)
85
- @string = string
86
- end
87
-
88
- def parse(parser)
89
- unless parser.next?(@string)
90
- raise Parser::Str::NotFound.new(parser, @string)
91
- end
92
-
93
- parser.consume(@string.size)
94
- end
95
-
96
- def to_s
97
- "str(#{@string.inspect})"
98
- end
99
- end
100
-
101
- class Absent < Atom
102
- def initialize(parent: nil)
103
- @parent = parent
104
- end
105
-
106
- def parse(parser)
107
- clone =
108
- Parser.new(
109
- root: self,
110
- input: parser.input,
111
- cursor: parser.cursor,
112
- buffer: parser.buffer
113
- )
114
- @parent&.parse(clone)
115
- rescue Parser::Interuption
116
- else
117
- raise Parser::Interuption.new(parser, self)
118
- end
119
-
120
- def to_s
121
- @parent ? "(#{@parent}).absent" : "absent"
122
- end
123
- end
124
-
125
- class Ignore < Atom
126
- def initialize(parent: nil)
127
- @parent = parent
128
- end
129
-
130
- def parse(parser)
131
- clone =
132
- Parser.new(
133
- root: self,
134
- input: parser.input,
135
- cursor: parser.cursor,
136
- buffer: parser.buffer
137
- )
138
- @parent&.parse(clone)
139
- parser.cursor = clone.cursor
140
- end
141
-
142
- def to_s
143
- @parent ? "#{@parent}.ignore" : "ignore"
144
- end
145
- end
146
-
147
- class Maybe < Atom
148
- def initialize(parent:)
149
- @parent = parent
150
- end
151
-
152
- def parse(parser)
153
- clone =
154
- Parser.new(
155
- root: self,
156
- input: parser.input,
157
- cursor: parser.cursor,
158
- buffer: parser.buffer
159
- )
160
-
161
- @parent.parse(clone)
162
- rescue Parser::Interuption
163
- else
164
- parser.buffer = clone.buffer
165
- parser.cursor = clone.cursor
166
- parser.output = clone.output
167
- end
168
-
169
- def to_s
170
- @parent ? "#{@parent}.maybe" : "maybe"
171
- end
172
- end
173
-
174
- class Aka < Atom
175
- def initialize(name:, parent:)
176
- @name = name
177
- @parent = parent
178
- end
179
-
180
- def parse(parser)
181
- clone =
182
- Parser.new(root: self, input: parser.input, cursor: parser.cursor)
183
-
184
- @parent.parse(clone)
185
-
186
- if clone.output?
187
- parser.output = Output.new(@name => clone.output)
188
- else
189
- parser.output[@name] = Output.new(clone.buffer)
190
- parser.buffer = ""
191
- end
192
-
193
- parser.cursor = clone.cursor
194
- end
195
-
196
- def to_s
197
- @parent ? "#{@parent}.aka(#{@name.inspect})" : "aka(#{@name.inspect})"
198
- end
199
- end
200
-
201
- class Or < Atom
202
- def initialize(left:, right:)
203
- @left = left
204
- @right = right
205
- end
206
-
207
- def parse(parser)
208
- left_clone =
209
- Parser.new(
210
- root: self,
211
- input: parser.input,
212
- cursor: parser.cursor,
213
- buffer: parser.buffer
214
- )
215
-
216
- right_clone =
217
- Parser.new(
218
- root: self,
219
- input: parser.input,
220
- cursor: parser.cursor,
221
- buffer: parser.buffer
222
- )
223
-
224
- begin
225
- @left.parse(left_clone)
226
- parser.cursor = left_clone.cursor
227
- parser.buffer = left_clone.buffer
228
- parser.output.merge(left_clone.output)
229
- rescue Parser::Interuption
230
- @right.parse(right_clone)
231
- parser.cursor = right_clone.cursor
232
- parser.buffer = right_clone.buffer
233
- parser.output.merge(right_clone.output)
234
- end
235
- end
236
-
237
- def to_s
238
- "((#{@left}) | (#{@right}))"
239
- end
240
- end
241
-
242
- class And < Atom
243
- def initialize(left:, right:)
244
- @left = left
245
- @right = right
246
- end
247
-
248
- def parse(parser)
249
- @left.parse(parser)
250
- right_clone =
251
- Parser.new(
252
- root: self,
253
- input: parser.input,
254
- cursor: parser.cursor,
255
- buffer: parser.buffer
256
- )
257
- @right.parse(right_clone)
258
- parser.cursor = right_clone.cursor
259
- parser.buffer = right_clone.buffer
260
-
261
- parser.output.merge(right_clone.output)
262
- end
263
-
264
- def to_s
265
- "#{@left} >> #{@right}".to_s
266
- end
267
- end
268
-
269
5
  def any
270
6
  Any.new
271
7
  end
@@ -315,7 +51,7 @@ class Language
315
51
  end
316
52
 
317
53
  def to_s
318
- ""
54
+ raise NotImplementedError, "#{self.class}#parse"
319
55
  end
320
56
 
321
57
  def inspect
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "../language"
2
4
 
3
- Language::Version = Gem::Version.new("0.6.0")
5
+ Language::Version = Gem::Version.new("0.6.1")
data/lib/language-ruby.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "zeitwerk"
2
4
 
3
5
  loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: false)
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Code
4
+ class Parser
5
+ class Nothing < Language
6
+ def nothing_keyword
7
+ str("nothing")
8
+ end
9
+
10
+ def root
11
+ nothing_keyword.aka(:nothing)
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ RSpec.describe Language do
18
+ it "works" do
19
+ expect(Code::Parser::Nothing.parse("nothing")).to eq({ nothing: "nothing" })
20
+ end
21
+ end
data/spec/spec_helper.rb CHANGED
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "../lib/language-ruby"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: language-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dorian Marié
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-10 00:00:00.000000000 Z
11
+ date: 2024-01-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: zeitwerk
@@ -30,13 +30,27 @@ executables: []
30
30
  extensions: []
31
31
  extra_rdoc_files: []
32
32
  files:
33
+ - ".gitignore"
34
+ - ".rspec"
35
+ - ".ruby-version"
36
+ - ".tool-versions"
33
37
  - Gemfile
38
+ - Gemfile.lock
39
+ - README.md
34
40
  - language-ruby.gemspec
35
41
  - lib/language-ruby.rb
36
42
  - lib/language.rb
37
43
  - lib/language/atom.rb
44
+ - lib/language/atom/absent.rb
45
+ - lib/language/atom/aka.rb
46
+ - lib/language/atom/and.rb
38
47
  - lib/language/atom/any.rb
48
+ - lib/language/atom/ignore.rb
49
+ - lib/language/atom/maybe.rb
50
+ - lib/language/atom/or.rb
39
51
  - lib/language/atom/repeat.rb
52
+ - lib/language/atom/str.rb
53
+ - lib/language/atom/then.rb
40
54
  - lib/language/output.rb
41
55
  - lib/language/parser.rb
42
56
  - lib/language/parser/absent.rb
@@ -47,6 +61,7 @@ files:
47
61
  - lib/language/parser/str.rb
48
62
  - lib/language/parser/str/not_found.rb
49
63
  - lib/language/version.rb
64
+ - spec/language_spec.rb
50
65
  - spec/spec_helper.rb
51
66
  homepage: https://github.com/dorianmariefr/language-ruby
52
67
  licenses:
@@ -67,9 +82,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
67
82
  - !ruby/object:Gem::Version
68
83
  version: '0'
69
84
  requirements: []
70
- rubygems_version: 3.4.14
85
+ rubygems_version: 3.5.3
71
86
  signing_key:
72
87
  specification_version: 4
73
88
  summary: A Parsing Expression Grammar (PEG) for making parsers
74
- test_files:
75
- - spec/spec_helper.rb
89
+ test_files: []