dolos 0.2.1 → 0.3.0

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: cfeffbbe4108e43ba81ccd210f2689910d310fc3947fe05ed22a9972e581e96a
4
- data.tar.gz: e181ccca4725008464fc92670b8120cf55262ba469d6ec494270081eb902c241
3
+ metadata.gz: 258d1d857ec1df4c70a50225e35114bbcc941b2901306d73db60543da1df93df
4
+ data.tar.gz: 3ec6f50215db6b4d719acc9552b5e6be34248452a7dcc4a6bef369e5e3c6ca2e
5
5
  SHA512:
6
- metadata.gz: 27fe73f34d41692d31c00d30bc03869cdefcef4ee785acbb72da12c9bceb85b78357da7c3d6d1435598b40fb635fb5e71d56254c18597c8d7d424748afc7c098
7
- data.tar.gz: 9dd78f5e313830742505bbeb1488ed643a700facc2193ed3e996eef795913a50bb660a2af2dcd7c9a73e6e5f84befa7e461b2cf10d4bd11f22d68901ecc59e9b
6
+ metadata.gz: be62167ed5bd8b4bc57b5670434afc4b58789749f4306e70399416467160ba5f3a86a11adab7056d1b60ad72f96f3ed44e51fdc90601500a368e7ca7d99b7e19
7
+ data.tar.gz: 5e8f105222057ff27d9daafc2b2b5ec2e5e7b96ee7be84c665214b1d84e52fa0c87d126020a5606418b1a41002f69edbcbdf2d6bd514667c6b1317318c162373
data/.rubocop.yml ADDED
@@ -0,0 +1,2 @@
1
+ AllCops:
2
+ DisabledByDefault: true
data/README.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # Dolos
2
+ [![Gem version](https://badge.fury.io/rb/dolos.svg)](https://rubygems.org/gems/dolos)
3
+ [![Build status](https://github.com/benetis/dolos/actions/workflows/ruby.yml/badge.svg)](https://github.com/benetis/dolos/actions)
2
4
 
3
- <img height="256" src="docs/dolos_stable_diff.png" width="256"/>
5
+
6
+ <img height="256" src="docs/images/dolos_stable_diff.png" width="256"/>
4
7
 
5
8
 
6
9
  ### Disclaimer
@@ -40,13 +43,13 @@ require 'dolos_common_parsers/common_parsers'
40
43
  include Dolos
41
44
  # frozen_string_literal: true
42
45
  require_relative 'dolos'
43
- require_relative 'dolos_common_parsers/common_parsers'
46
+ require_relative 'dolos_parsers/common_parsers'
44
47
 
45
48
  include Dolos
46
49
 
47
50
  # Include common parsers
48
51
  # In future this can be more structured, moved them to separate module to prevent breaking changes
49
- include Dolos::CommonParsers
52
+ include Dolos::Common
50
53
 
51
54
  # Library usage example
52
55
  # Parse out a name and address from a letter
data/docs/.nojekyll ADDED
File without changes
data/docs/README.md ADDED
@@ -0,0 +1,22 @@
1
+ # Dolos
2
+
3
+ ## What is Dolos?
4
+ Dolos is parser combinator library for Ruby. It is inspired by FastParse and Scala Parser Combinators.
5
+
6
+ ## What are parser combinators?
7
+ Parser combinators are a way to build parsers from smaller parsers. For example, you can build a parser for a number from a parser for a digit.
8
+ This is a very simple example, but it can be used to build more complex parsers.
9
+ Parsers are lazy and only run when needed. This allows to build complex parsers before passing input to them.
10
+ ```ruby
11
+ hello = string("Hello")
12
+ greeting = hello >> c(" ") >> string("Ruby developer!")
13
+ greeting.run("Hello Ruby developer!") # => Success
14
+ ```
15
+
16
+ ## What's different from alternatives?
17
+ This library focuses on two things:
18
+ - Parsers integrate well into Ruby code. There is no need to keep them in separate classes.
19
+ - Fine grained control over parsers. You can `map` and adjust each parser separately
20
+ - Two ways of capturing values: traditional `>>`, other product operators to construct value and `capture!`
21
+ - For simple parsers `capture!` can be used to very quickly capture values into flat arrays
22
+ - Running parsers will not throw exceptions and instead return a result object. Exceptions don't play well with parsing.
data/docs/_sidebar.md ADDED
@@ -0,0 +1,4 @@
1
+ * [Home](/)
2
+ * [Getting started](getting_started.md)
3
+ * [Installation](getting_started.md#installation)
4
+ * [Usage](getting_started.md#usage)
@@ -0,0 +1,52 @@
1
+ # Getting started
2
+
3
+ ## Installation
4
+
5
+ Install the gem and add it to your Gemfile:
6
+ ```shell
7
+ $ bundle add dolos
8
+ ```
9
+ Or manually:
10
+ ```ruby
11
+ gem 'dolos'
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ Two things to do:
17
+ - require library
18
+ - include module `Dolos` and `Dolos::Common`
19
+
20
+ ```ruby
21
+ require 'dolos'
22
+
23
+ include Dolos
24
+ include Dolos::Common # Common parsers
25
+ ```
26
+
27
+ ### Basic parsers
28
+
29
+ A simple parser which matches one word.
30
+
31
+ ```ruby
32
+ require 'dolos'
33
+ include Dolos
34
+
35
+ hello = c("Hello") # c("") is an alias for string(""). Can be read as: case-sensitive string match
36
+
37
+ hello.run("Hello").success? # => true
38
+
39
+ hello.run("hello").success? # => failure
40
+ ```
41
+
42
+ After defining parser, it can be ran with `run('my-input')` method. It returns a `Result` object.
43
+
44
+ ### Result
45
+
46
+ Result can be either `Success` or `Failure`. It can be checked with `success?` or `failure?` methods.
47
+
48
+ Success will also have `value` property which will contain the result of the parser. There is also `captures`, but
49
+ that's for later.
50
+
51
+
52
+ Failure will have `inspect` method which will return a string with the error message. It will show error position as well.
data/docs/index.html ADDED
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Document</title>
6
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
7
+ <meta name="description" content="Description">
8
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
9
+ <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css">
10
+ </head>
11
+ <body>
12
+ <div id="app"></div>
13
+ <script>
14
+ window.$docsify = {
15
+ name: '',
16
+ repo: ''
17
+ }
18
+ window.$docsify = {
19
+ loadSidebar: true
20
+ }
21
+ </script>
22
+ <!-- Docsify v4 -->
23
+ <script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
24
+ <script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-ruby.min.js"></script>
25
+ </body>
26
+ </html>
data/examples/letter.rb CHANGED
@@ -6,7 +6,7 @@ include Dolos
6
6
 
7
7
  # Include common parsers
8
8
  # In future this can be more structured, moved them to separate module to prevent breaking changes
9
- include Dolos::CommonParsers
9
+ include Dolos::Common
10
10
 
11
11
  # Library usage example
12
12
  # Parse out a name and address from a letter
@@ -1,7 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dolos
4
- module CommonParsers
4
+ # Common parsers
5
+ # Separated from the main library to improve them later on
6
+ # These will change, new ones will be added. Once API stabilises, we will see what to do
7
+ # We have to be careful what is in the scope when we include this main module
8
+ # Probably a package of parsers following some RFC will be added as well.
9
+ # Keeping them separate for now
10
+ module Common
5
11
  def ws
6
12
  regex(/\s/)
7
13
  end
data/lib/dolos/parsers.rb CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  module Dolos
4
4
  module Parsers
5
+
6
+ # String parser
7
+ # Matches exactly the given string
8
+ # string('hello').run('hello') => Success.new('hello', 5)
9
+ # Alias: c, for case-sensitive. Ex: c('hello').run('hello') => Success.new('hello', 5)
5
10
  def string(str)
6
11
  utf8_str = str.encode('UTF-8')
7
12
 
@@ -21,9 +26,12 @@ module Dolos
21
26
  end
22
27
  end
23
28
  end
24
-
25
29
  alias_method :c, :string
26
30
 
31
+ # Regex parser
32
+ # Accepts a regex, matches the regex against the input
33
+ # parser = regex(/\d+/)
34
+ # result = parser.run('123') # => Success.new('123', 3)
27
35
  def regex(pattern)
28
36
  Parser.new do |state|
29
37
  state.input.mark_offset
@@ -41,6 +49,8 @@ module Dolos
41
49
  end
42
50
  end
43
51
 
52
+ # Matches any character
53
+ # any_char.run('a') # => Success.new('a', 1)
44
54
  def any_char
45
55
  Parser.new do |state|
46
56
  state.input.mark_offset
@@ -62,6 +72,7 @@ module Dolos
62
72
  end
63
73
 
64
74
  # Matches any character in a string
75
+ # Passed string can be imagined as a set of characters
65
76
  # Example:
66
77
  # char_in('abc').run('b') # => Success.new('b', 1)
67
78
  def char_in(characters_string)
data/lib/dolos/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dolos
4
- VERSION = "0.2.1"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/dolos.rb CHANGED
@@ -15,16 +15,24 @@ module Dolos
15
15
  @parser_proc = block
16
16
  end
17
17
 
18
+ # Run the parser with the given input
19
+ # Returns a Result<Success|Failure>
20
+ # string("hello").run("hello") => Success.new("hello", 5)
18
21
  def run(input)
19
22
  run_with_state(ParserState.new(input))
20
23
  end
21
24
 
25
+
22
26
  def run_with_state(state)
23
27
  result = @parser_proc.call(state)
24
28
  state.last_success_position = state.input.offset if result.success?
25
29
  result
26
30
  end
27
31
 
32
+ # Capture the result of the parser
33
+ # p = string("hello").capture!
34
+ # p.run("hello").captures => ["hello"]
35
+ # Captures is a flat array of all captured values
28
36
  def capture!(wrap_in = nil)
29
37
  Parser.new do |state|
30
38
  result = run_with_state(state)
@@ -32,7 +40,10 @@ module Dolos
32
40
  end
33
41
  end
34
42
 
35
- # Will call `map` on captures
43
+ # Map the captures of the parser
44
+ # p = string("hello").map_captures { |captures| captures.map(&:upcase) }
45
+ # p.run("hello") => Success.new("hello", 5, ["HELLO"])
46
+ # This only maps over captures, not the value
36
47
  def map_captures(&block)
37
48
  Parser.new do |state|
38
49
  result = run_with_state(state)
@@ -40,7 +51,9 @@ module Dolos
40
51
  end
41
52
  end
42
53
 
43
- # Will call block on tuple of value
54
+ # Map the result of the parser
55
+ # p = string("hello").map { |s| s.upcase }
56
+ # p.run("hello") => Success.new("HELLO", 5)
44
57
  def map(&block)
45
58
  Parser.new do |state|
46
59
  result = run_with_state(state)
@@ -48,6 +61,7 @@ module Dolos
48
61
  end
49
62
  end
50
63
 
64
+ # Combine the result of the parser with another parser
51
65
  def combine(&block)
52
66
  Parser.new do |state|
53
67
  result = run_with_state(state)
@@ -62,12 +76,10 @@ module Dolos
62
76
  end
63
77
  end
64
78
 
65
- def flatten
66
- map_captures do |captures|
67
- captures.flatten
68
- end
69
- end
70
-
79
+ # Combine the result of the parser with another parser
80
+ # Has an alias of `&`
81
+ # p = string("hello") & string("world")
82
+ # p.run("helloworld") => Success.new(["hello", "world"], 10)
71
83
  def product(other_parser)
72
84
  combine do |value1, capture1|
73
85
  other_parser.map do |value2|
@@ -79,6 +91,10 @@ module Dolos
79
91
  end
80
92
  alias_method :&, :product
81
93
 
94
+
95
+ # Combine the result of the parser with another parser
96
+ # Discards the result of the second parser
97
+ # p = string("hello") << string("world")
82
98
  def product_l(other_parser)
83
99
  combine do |value1, capture1|
84
100
  other_parser.map do |_|
@@ -89,6 +105,9 @@ module Dolos
89
105
  end
90
106
  end
91
107
 
108
+ # Combine the result of the parser with another parser
109
+ # Discards the result of the first parser
110
+ # p = string("hello") >> string("world")
92
111
  def product_r(other_parser)
93
112
  combine do |_, capture1|
94
113
  other_parser.map do |value2|
@@ -102,6 +121,10 @@ module Dolos
102
121
  alias_method :<<, :product_l
103
122
  alias_method :>>, :product_r
104
123
 
124
+ # Combine the result of the parser with another parser
125
+ # If the first parser fails, it will try the second parser
126
+ # p = string("hello") | string("world") | string("!")
127
+ # p.run("hello") => Success.new("hello", 5)
105
128
  def choice(other_parser)
106
129
  Parser.new do |state|
107
130
  result = run_with_state(state)
@@ -114,6 +137,9 @@ module Dolos
114
137
  end
115
138
  alias_method :|, :choice
116
139
 
140
+
141
+ # Repeat the parser n times
142
+ # Separator is optional, its another parser that will be run between each repetition
117
143
  # rep0 # 0 or more
118
144
  # rep # 1 or more
119
145
  # rep(n = 2) # exactly 2
@@ -156,11 +182,17 @@ module Dolos
156
182
  end
157
183
  end
158
184
  end
185
+
186
+ # Repeat the parser zero or more times
187
+ # c(" ").rep0.run(" ") => Success.new([" ", " ", " "], 3)
159
188
  def zero_or_more
160
189
  repeat(n_min: 0, n_max: Float::INFINITY)
161
190
  end
162
191
  alias_method :rep0, :zero_or_more
163
192
 
193
+ # Repeat the parser one or more times
194
+ # Same as rep0, but must match at least once
195
+ # c(" ").rep.run("A") => Failure.new("...")
164
196
  def one_or_more(exactly = nil)
165
197
  if exactly.nil?
166
198
  repeat(n_min: 1, n_max: Float::INFINITY)
@@ -170,6 +202,8 @@ module Dolos
170
202
  end
171
203
  alias_method :rep, :one_or_more
172
204
 
205
+ # Make parser optional
206
+ # c(" ").opt.run("A") => Success.new([], 0)
173
207
  def optional
174
208
  Parser.new do |state|
175
209
  result = run_with_state(state.dup)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dolos
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - benetis
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-08-22 00:00:00.000000000 Z
11
+ date: 2023-08-23 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Parser combinators library for Ruby. In active development, not stable
14
14
  yet.
@@ -19,6 +19,7 @@ extensions: []
19
19
  extra_rdoc_files: []
20
20
  files:
21
21
  - ".rspec"
22
+ - ".rubocop.yml"
22
23
  - CHANGELOG.md
23
24
  - LICENSE.txt
24
25
  - README.md
@@ -27,15 +28,20 @@ files:
27
28
  - benchmarks/json/nested_json_166.json
28
29
  - benchmarks/json/nested_json_1m.json
29
30
  - benchmarks/letter.rb
30
- - docs/dolos_stable_diff.png
31
+ - docs/.nojekyll
32
+ - docs/README.md
33
+ - docs/_sidebar.md
34
+ - docs/getting_started.md
35
+ - docs/images/dolos_stable_diff.png
36
+ - docs/index.html
31
37
  - examples/letter.rb
32
38
  - lib/dolos.rb
39
+ - lib/dolos/common.rb
33
40
  - lib/dolos/parser_state.rb
34
41
  - lib/dolos/parsers.rb
35
42
  - lib/dolos/result.rb
36
43
  - lib/dolos/string_io_wrapper.rb
37
44
  - lib/dolos/version.rb
38
- - lib/dolos_common_parsers/common_parsers.rb
39
45
  - sig/dolos.rbs
40
46
  - sig/dolos/common_parsers.rbs
41
47
  - sig/dolos/parser.rbs