parse_queue 0.1.0 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/README.md +47 -11
- data/images/queue.png +0 -0
- data/lib/parse_queue.rb +54 -34
- data/lib/parse_queue/exceptions.rb +0 -2
- data/lib/parse_queue/version.rb +1 -3
- data/parse_queue.gemspec +5 -3
- data/rakefile.rb +11 -0
- data/reek.txt +1 -0
- metadata +17 -16
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: e2a1861627deadb0bac32e7b807cad91fc82d90d5758c5b4969f3ede031bcbdb
|
|
4
|
+
data.tar.gz: 4cfd26f3b0c455a6394d10b325b12d73dce63f8b5d8e8271d3d4b73da49af594
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 95750f6139a58734609f072f253bcd97eedfc7af81d5dceb6e714ee57e092bba7b71e42ce05bde2688f81a0c7636f02c612d29f4bd18673ff2171c5be10a119c
|
|
7
|
+
data.tar.gz: 436b508221175b802ae1dee447e1a6e76ca2e07850d1d718ffb8c9fc80a2f43fa6e2a82f79b2af893db91ff78530db190ba69a7230ddfc1d6e29adfc401642dc
|
data/README.md
CHANGED
|
@@ -7,6 +7,16 @@ simple queue, it supports backing up or falling back to earlier states allowing
|
|
|
7
7
|
the parser to try other paths in the syntax tree when one path runs into a
|
|
8
8
|
dead end.
|
|
9
9
|
|
|
10
|
+
The parse queue was created to simplify the design of both the lexical analyzer
|
|
11
|
+
and the parser. Parsers often have a built-in limited "look-ahead" of tokens.
|
|
12
|
+
This can be seen in parser names like LL(0), LL(1), LR(1), LALR(n), etc. The
|
|
13
|
+
parse queue provides for a flexible look-ahead removing this burden from other
|
|
14
|
+
compiler components.
|
|
15
|
+
|
|
16
|
+
The operation of the parse queue is summarized in the following diagram:
|
|
17
|
+
|
|
18
|
+

|
|
19
|
+
|
|
10
20
|
## Installation
|
|
11
21
|
|
|
12
22
|
Add this line to your application's Gemfile:
|
|
@@ -34,11 +44,21 @@ When creating a parse queue, an optional block parameter is passed in. This is
|
|
|
34
44
|
called whenever more queue items are required. For example:
|
|
35
45
|
|
|
36
46
|
```ruby
|
|
37
|
-
|
|
47
|
+
def open_file_tokenized(name)
|
|
48
|
+
txt = IO.readlines(name, nil)[0]
|
|
49
|
+
lex = LexicalAnalayzer.new(text: txt, rules: LEXICAL_RULES)
|
|
50
|
+
ParseQueue.new { lex.get }
|
|
51
|
+
end
|
|
38
52
|
```
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
53
|
+
This example above is a method that reads in the named file, creates an
|
|
54
|
+
analyzer on it (see the
|
|
55
|
+
[lexical_analyzer](https://rubygems.org/gems/lexical_analyzer)
|
|
56
|
+
gem for more details) and then uses that as the source for the parse queue.
|
|
57
|
+
The queue is returned for use by the compiler's parser.
|
|
58
|
+
|
|
59
|
+
Note: The constant LEXICAL_RULES is a set of rules used to define the tokens
|
|
60
|
+
extracted by the lexical analyzer. As such it is not discussed further here.
|
|
61
|
+
See that gem for more details on how rules are constructed.
|
|
42
62
|
|
|
43
63
|
#### Getting a queued item:
|
|
44
64
|
|
|
@@ -50,6 +70,12 @@ Getting an item from the queue is done with the get method. For example:
|
|
|
50
70
|
This method returns the next unread item from the queue. Note that if no items
|
|
51
71
|
are available, the exception **ParseQueueNoFwd** is raised.
|
|
52
72
|
|
|
73
|
+
Note: The get! method is a get without backtracking. In effect it is a get
|
|
74
|
+
followed by a shift (see Shifting below).
|
|
75
|
+
|
|
76
|
+
```ruby
|
|
77
|
+
item = pq.get!
|
|
78
|
+
```
|
|
53
79
|
|
|
54
80
|
#### Backtracking:
|
|
55
81
|
|
|
@@ -82,7 +108,7 @@ a value saved off at an earlier point of the processing. For example:
|
|
|
82
108
|
|
|
83
109
|
#### Shifting
|
|
84
110
|
|
|
85
|
-
So far, items have been retained in the queue, even
|
|
111
|
+
So far, items have been retained in the queue, even after they are done being
|
|
86
112
|
processed. For large files, this may use a large amount of memory. To avoid
|
|
87
113
|
this, used items need to be shifted out of the parse queue. This can be done as
|
|
88
114
|
follows:
|
|
@@ -96,9 +122,9 @@ follows:
|
|
|
96
122
|
}
|
|
97
123
|
```
|
|
98
124
|
Note how the try! block returns a value called success. If this value is false
|
|
99
|
-
or nil, the parse queue is rolled back to its condition at the start of the
|
|
100
|
-
block. Otherwise, any changes to the parse queue are retained and
|
|
101
|
-
items are removed.
|
|
125
|
+
or nil, the parse queue is rolled back to its condition at the start of the
|
|
126
|
+
try! block. Otherwise, any changes to the parse queue are retained and
|
|
127
|
+
processed items are removed.
|
|
102
128
|
|
|
103
129
|
This too can be done manually as shown below:
|
|
104
130
|
|
|
@@ -116,11 +142,21 @@ This too can be done manually as shown below:
|
|
|
116
142
|
Note that if an attempt is made to fall back to data that has been shifted out,
|
|
117
143
|
a **ParseQueueNoRev** exception is raised.
|
|
118
144
|
|
|
145
|
+
#### Exceptions
|
|
146
|
+
|
|
147
|
+
The parse queue uses the following exception classes:
|
|
148
|
+
|
|
149
|
+
Exception # From Ruby.
|
|
150
|
+
StandardError # From Ruby.
|
|
151
|
+
ParseQueueError # The abstract root of parse queue exceptions.
|
|
152
|
+
ParseQueueNoFwd # Error: Can't go forward.
|
|
153
|
+
ParseQueueNoRev # Error: Can't fall back.
|
|
154
|
+
|
|
119
155
|
## Contributing
|
|
120
156
|
|
|
121
157
|
#### Plan A
|
|
122
158
|
|
|
123
|
-
1. Fork it ( https://github.com/PeterCamilleri/
|
|
159
|
+
1. Fork it ( https://github.com/PeterCamilleri/parse_queue/fork )
|
|
124
160
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
125
161
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
126
162
|
4. Push to the branch (`git push origin my-new-feature`)
|
|
@@ -134,10 +170,10 @@ aspect that could use some TLC or a suggestion or an idea.
|
|
|
134
170
|
## License
|
|
135
171
|
|
|
136
172
|
The gem is available as open source under the terms of the
|
|
137
|
-
[MIT License](
|
|
173
|
+
[MIT License](./LICENSE.txt).
|
|
138
174
|
|
|
139
175
|
## Code of Conduct
|
|
140
176
|
|
|
141
177
|
Everyone interacting in the ParseQueue project’s codebases, issue trackers,
|
|
142
178
|
chat rooms and mailing lists is expected to follow the
|
|
143
|
-
[code of conduct](
|
|
179
|
+
[code of conduct](./CODE_OF_CONDUCT.md).
|
data/images/queue.png
ADDED
|
Binary file
|
data/lib/parse_queue.rb
CHANGED
|
@@ -1,54 +1,61 @@
|
|
|
1
|
-
# coding: utf-8
|
|
2
|
-
|
|
3
1
|
# The Ruby Compiler Toolkit Project - Parse Queue
|
|
4
2
|
# A queue for compiler objects between parser layers.
|
|
5
3
|
|
|
6
4
|
require_relative "parse_queue/exceptions"
|
|
7
5
|
require_relative "parse_queue/version"
|
|
8
6
|
|
|
7
|
+
# The RCTP queue for parser token flow with backtracking.
|
|
9
8
|
class ParseQueue
|
|
10
9
|
|
|
11
10
|
# The current read point of the queue.
|
|
12
11
|
attr_reader :position
|
|
13
12
|
|
|
14
|
-
#
|
|
15
|
-
|
|
13
|
+
#The default fetch block
|
|
14
|
+
DFB = Proc.new { false }
|
|
16
15
|
|
|
17
16
|
# Set up the parser queue.
|
|
18
17
|
def initialize(&fetch)
|
|
19
|
-
@fetch
|
|
18
|
+
@fetch = fetch
|
|
20
19
|
@buffer = []
|
|
21
20
|
@offset = @position = 0
|
|
22
21
|
end
|
|
23
22
|
|
|
24
23
|
# How many unread items are in this parse queue?
|
|
25
|
-
def
|
|
26
|
-
|
|
24
|
+
def fwd_count
|
|
25
|
+
index_limit - @position
|
|
27
26
|
end
|
|
28
27
|
|
|
29
|
-
#
|
|
30
|
-
def
|
|
31
|
-
@
|
|
28
|
+
# How many already read items are still in this parse queue?
|
|
29
|
+
def rev_count
|
|
30
|
+
@position - @offset
|
|
32
31
|
end
|
|
33
32
|
|
|
34
33
|
# Get an item from the buffer.
|
|
35
34
|
def get
|
|
36
|
-
if @position
|
|
37
|
-
item = @fetch.call
|
|
38
|
-
fail ParseQueueNoFwd unless item
|
|
39
|
-
@buffer << item
|
|
40
|
-
end
|
|
35
|
+
@buffer << fetch_one if @position == index_limit
|
|
41
36
|
|
|
42
|
-
result = @buffer[
|
|
37
|
+
result = @buffer[rev_count]
|
|
43
38
|
@position += 1
|
|
44
39
|
result
|
|
45
40
|
end
|
|
46
41
|
|
|
47
|
-
# Get
|
|
48
|
-
def
|
|
42
|
+
# Get an item and shift the buffer.
|
|
43
|
+
def get!
|
|
44
|
+
result = get
|
|
45
|
+
shift
|
|
46
|
+
result
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Fetch all possible items.
|
|
50
|
+
def fetch_all
|
|
49
51
|
loop do
|
|
50
52
|
item = @fetch.call
|
|
51
|
-
|
|
53
|
+
|
|
54
|
+
unless item
|
|
55
|
+
@fetch = DFB
|
|
56
|
+
return
|
|
57
|
+
end
|
|
58
|
+
|
|
52
59
|
@buffer << item
|
|
53
60
|
end
|
|
54
61
|
end
|
|
@@ -60,40 +67,53 @@ class ParseQueue
|
|
|
60
67
|
end
|
|
61
68
|
|
|
62
69
|
# Undo the last get.
|
|
63
|
-
def
|
|
64
|
-
@position -=
|
|
70
|
+
def unget(count=1)
|
|
71
|
+
@position -= count
|
|
65
72
|
validate_position
|
|
66
73
|
end
|
|
67
74
|
|
|
68
75
|
# Release any items before the current item.
|
|
69
76
|
def shift
|
|
70
|
-
@buffer.shift(
|
|
77
|
+
@buffer.shift(rev_count)
|
|
71
78
|
@offset = @position
|
|
72
79
|
end
|
|
73
80
|
|
|
74
81
|
# Try to process some items with roll back on failure.
|
|
75
82
|
def try(&block)
|
|
76
83
|
save = @position
|
|
77
|
-
|
|
78
|
-
|
|
84
|
+
self.position = save unless (result = block.call)
|
|
85
|
+
result
|
|
79
86
|
end
|
|
80
87
|
|
|
81
|
-
#
|
|
88
|
+
# Process some items with a shift on success and a roll back on failure.
|
|
82
89
|
def try!(&block)
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if block.call
|
|
86
|
-
shift
|
|
87
|
-
else
|
|
88
|
-
@position = save
|
|
89
|
-
validate_position
|
|
90
|
-
end
|
|
90
|
+
shift if (result = try(&block))
|
|
91
|
+
result
|
|
91
92
|
end
|
|
92
93
|
|
|
94
|
+
private
|
|
95
|
+
|
|
93
96
|
# Is this a valid position?
|
|
94
97
|
def validate_position
|
|
95
98
|
fail ParseQueueNoRev if @position < @offset
|
|
96
|
-
fail ParseQueueNoFwd if @position >=
|
|
99
|
+
fail ParseQueueNoFwd if @position >= index_limit
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# The first index past the end of the array
|
|
103
|
+
def index_limit
|
|
104
|
+
@buffer.length + @offset
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Fetch a single item.
|
|
108
|
+
def fetch_one
|
|
109
|
+
item = @fetch.call
|
|
110
|
+
|
|
111
|
+
unless item
|
|
112
|
+
@fetch = DFB
|
|
113
|
+
fail ParseQueueNoFwd
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
item
|
|
97
117
|
end
|
|
98
118
|
|
|
99
119
|
end
|
data/lib/parse_queue/version.rb
CHANGED
data/parse_queue.gemspec
CHANGED
|
@@ -18,8 +18,10 @@ Gem::Specification.new do |spec|
|
|
|
18
18
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test)/}) }
|
|
19
19
|
spec.require_paths = ["lib"]
|
|
20
20
|
|
|
21
|
-
spec.
|
|
22
|
-
|
|
21
|
+
spec.required_ruby_version = '>=2.3.0'
|
|
22
|
+
|
|
23
|
+
spec.add_development_dependency "bundler", ">= 2.1.0"
|
|
24
|
+
spec.add_development_dependency "rake", ">= 12.3.3"
|
|
23
25
|
spec.add_development_dependency "minitest", "~> 5.0"
|
|
24
|
-
spec.add_development_dependency '
|
|
26
|
+
spec.add_development_dependency 'reek', "~> 5.0.2"
|
|
25
27
|
end
|
data/rakefile.rb
CHANGED
|
@@ -8,3 +8,14 @@ Rake::TestTask.new(:test) do |t|
|
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
task :default => :test
|
|
11
|
+
|
|
12
|
+
desc "Run a scan for smelly code!"
|
|
13
|
+
task :reek do |t|
|
|
14
|
+
`reek --no-color lib > reek.txt`
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
desc "What version of parse queue is this?"
|
|
18
|
+
task :vers do |t|
|
|
19
|
+
puts
|
|
20
|
+
puts "parse_queue version = #{ParseQueue::VERSION}"
|
|
21
|
+
end
|
data/reek.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0 total warnings
|
metadata
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: parse_queue
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- PeterCamilleri
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2021-05-19 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- - "
|
|
17
|
+
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version:
|
|
19
|
+
version: 2.1.0
|
|
20
20
|
type: :development
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
|
-
- - "
|
|
24
|
+
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version:
|
|
26
|
+
version: 2.1.0
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: rake
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
|
-
- - "
|
|
31
|
+
- - ">="
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version:
|
|
33
|
+
version: 12.3.3
|
|
34
34
|
type: :development
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
|
-
- - "
|
|
38
|
+
- - ">="
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version:
|
|
40
|
+
version: 12.3.3
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: minitest
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -53,19 +53,19 @@ dependencies:
|
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '5.0'
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
|
-
name:
|
|
56
|
+
name: reek
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
58
58
|
requirements:
|
|
59
59
|
- - "~>"
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version:
|
|
61
|
+
version: 5.0.2
|
|
62
62
|
type: :development
|
|
63
63
|
prerelease: false
|
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
|
66
66
|
- - "~>"
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
|
-
version:
|
|
68
|
+
version: 5.0.2
|
|
69
69
|
description: The RCTP object queue for moving compiler tokens with nestable backtrack
|
|
70
70
|
capability.
|
|
71
71
|
email:
|
|
@@ -79,11 +79,13 @@ files:
|
|
|
79
79
|
- Gemfile
|
|
80
80
|
- LICENSE.txt
|
|
81
81
|
- README.md
|
|
82
|
+
- images/queue.png
|
|
82
83
|
- lib/parse_queue.rb
|
|
83
84
|
- lib/parse_queue/exceptions.rb
|
|
84
85
|
- lib/parse_queue/version.rb
|
|
85
86
|
- parse_queue.gemspec
|
|
86
87
|
- rakefile.rb
|
|
88
|
+
- reek.txt
|
|
87
89
|
homepage: https://github.com/PeterCamilleri/parse_queue
|
|
88
90
|
licenses:
|
|
89
91
|
- MIT
|
|
@@ -96,15 +98,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
96
98
|
requirements:
|
|
97
99
|
- - ">="
|
|
98
100
|
- !ruby/object:Gem::Version
|
|
99
|
-
version:
|
|
101
|
+
version: 2.3.0
|
|
100
102
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
101
103
|
requirements:
|
|
102
104
|
- - ">="
|
|
103
105
|
- !ruby/object:Gem::Version
|
|
104
106
|
version: '0'
|
|
105
107
|
requirements: []
|
|
106
|
-
|
|
107
|
-
rubygems_version: 2.5.2
|
|
108
|
+
rubygems_version: 3.2.17
|
|
108
109
|
signing_key:
|
|
109
110
|
specification_version: 4
|
|
110
111
|
summary: The RCTP object queue for connecting parser steps.
|