radd_djur 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 81c593af1a6b8fa7adbc48d74bd12a0d452cc3b8
4
+ data.tar.gz: 9c2d118ba3047f06b2745f69e73ea1f3b777a2d3
5
+ SHA512:
6
+ metadata.gz: e665757f618377aeff4b7556fb0ed3c6d77f1e290701f82280c9768e69e481e7f0d0031b71d2cc2dd5b93f546b31e6a84322c0fdbe86be0ed893cab2ac907a7c
7
+ data.tar.gz: 1ef6ebb0611545820d957cd29c2c309504942238fab8fdfce57afd459848f6edc9d4dbab5e50f14b7d183c6bcf601398ae85ee85a8ba13389556d0f09f32a0eb
data/README.md ADDED
@@ -0,0 +1,101 @@
1
+ radd\_djur - Packrat parser combinator library for Ruby
2
+ =======================================================
3
+
4
+ This project aims to provide immutable data structures for Ruby.
5
+
6
+ Install
7
+ -------
8
+
9
+ ```bash
10
+ $ gem install radd_djur
11
+ ```
12
+
13
+ Documentation
14
+ -------------
15
+
16
+ * [API Reference](http://rubydoc.info/github/shugo/radd_djur/frames)
17
+
18
+ Example
19
+ -------
20
+
21
+ require "radd_djur"
22
+
23
+ # Activate refinements for radd_djur DSL.
24
+ # In the DSL, a Ruby symbol represents a nonterminal symbol, and a Ruby
25
+ # string represents a terminal symbol.
26
+ using RaddDjur::DSL
27
+
28
+ # Define a new grammar, whose start symbol is additive.
29
+ g = RaddDjur::Grammar.new(:additive) {
30
+
31
+ # Grammar#define defines a new parsing rule for a nonterminal symbol.
32
+ # The first argument is the name of the nonterminal symbol.
33
+ # In the following comments, parsing rules are expressed in PEG.
34
+
35
+ # additive <- multitive '+' additive / multitive
36
+ define :additive do
37
+ :multitive.bind { |x|
38
+ "+".bind {
39
+ :additive.bind { |y|
40
+ ret x + y
41
+ }
42
+ }
43
+ } / :multitive
44
+ end
45
+
46
+ # multitive <- primary '*' multitive / primary
47
+ define :multitive do
48
+ :primary.bind { |x|
49
+ "*".bind {
50
+ :multitive.bind { |y|
51
+ ret x * y
52
+ }
53
+ }
54
+ } / :primary
55
+ end
56
+
57
+ # primary <- '(' additive ')' / digits
58
+ define :primary do
59
+ "(".bind {
60
+ :additive.bind { |x|
61
+ ")".bind {
62
+ ret x
63
+ }
64
+ }
65
+ } / :digits
66
+ end
67
+
68
+ # digits <- [0-9]+
69
+ define :digits do
70
+ (?0..?9).one_or_more.bind { |xs|
71
+ ret xs.foldl1(&:+).to_i
72
+ }
73
+ end
74
+ }
75
+ p g.parse("2*(3+4)")
76
+
77
+ License
78
+ -------
79
+
80
+ (The MIT License)
81
+
82
+ Copyright (c) 2013 Shugo Maeda
83
+
84
+ Permission is hereby granted, free of charge, to any person obtaining
85
+ a copy of this software and associated documentation files (the
86
+ 'Software'), to deal in the Software without restriction, including
87
+ without limitation the rights to use, copy, modify, merge, publish,
88
+ distribute, sublicense, and/or sell copies of the Software, and to
89
+ permit persons to whom the Software is furnished to do so, subject to
90
+ the following conditions:
91
+
92
+ The above copyright notice and this permission notice shall be
93
+ included in all copies or substantial portions of the Software.
94
+
95
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
96
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
97
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
98
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
99
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
100
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
101
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,53 @@
1
+ module RaddDjur
2
+ module DSL
3
+ refine Object do
4
+ def bind(&block)
5
+ to_parser.bind(&block)
6
+ end
7
+
8
+ def /(p2)
9
+ to_parser / p2
10
+ end
11
+
12
+ def optional
13
+ to_parser.optional
14
+ end
15
+
16
+ def zero_or_more
17
+ to_parser.zero_or_more
18
+ end
19
+
20
+ def one_or_more
21
+ to_parser.one_or_more
22
+ end
23
+
24
+ def to_parser
25
+ raise TypeError, "#{self.class} can't be converted to a Parser"
26
+ end
27
+ end
28
+
29
+ refine Symbol do
30
+ def to_parser
31
+ Grammar::Parser.new(&self)
32
+ end
33
+ end
34
+
35
+ refine String do
36
+ def to_parser
37
+ Grammar::Parsers.string(self)
38
+ end
39
+ end
40
+
41
+ refine Range do
42
+ def to_parser
43
+ Grammar::Parsers.any_char.bind { |c|
44
+ if self.cover?(c)
45
+ Grammar::Parsers.ret(c)
46
+ else
47
+ Grammar::Parsers.fail
48
+ end
49
+ }
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,191 @@
1
+ require "immutable"
2
+ require "radd_djur/dsl"
3
+
4
+ using RaddDjur::DSL
5
+
6
+ module RaddDjur
7
+ class Grammar
8
+ class Result
9
+ end
10
+
11
+ class Parsed < Result
12
+ attr_reader :value, :remainder
13
+
14
+ def initialize(value, remainder)
15
+ @value = value
16
+ @remainder = remainder
17
+ end
18
+
19
+ def succeeded?
20
+ true
21
+ end
22
+ end
23
+
24
+ NO_PARSE = Result.new
25
+
26
+ def NO_PARSE.succeeded?
27
+ false
28
+ end
29
+
30
+ class ParseError < StandardError; end
31
+
32
+ class Derivs
33
+ include Immutable
34
+
35
+ def initialize(grammar, str)
36
+ @grammar = grammar
37
+ @str = str
38
+ @memo = {}
39
+ end
40
+
41
+ def char
42
+ @memo[:char] ||=
43
+ Promise.delay {
44
+ if @str.empty?
45
+ NO_PARSE
46
+ else
47
+ Parsed.new(@str[0], Derivs.new(@grammar, @str[1..-1]))
48
+ end
49
+ }
50
+ end
51
+
52
+ def method_missing(mid, *args)
53
+ @memo[mid] ||= @grammar.parser(mid).parse(self)
54
+ end
55
+ end
56
+
57
+ module Parsers
58
+ include Immutable
59
+
60
+ module_function
61
+
62
+ def ret(value)
63
+ Parser.new { |d|
64
+ Promise.eager(Parsed.new(value, d))
65
+ }
66
+ end
67
+
68
+ def fail
69
+ Parser.new { |d|
70
+ Promise.eager(NO_PARSE)
71
+ }
72
+ end
73
+
74
+ def any_char
75
+ Parser.new(&:char)
76
+ end
77
+
78
+ def char(ch)
79
+ any_char.bind { |c|
80
+ if c == ch
81
+ ret c
82
+ else
83
+ fail
84
+ end
85
+ }
86
+ end
87
+
88
+ def string(str)
89
+ if str.empty?
90
+ ret ""
91
+ else
92
+ char(str[0]).bind { |c|
93
+ string(str[1..-1]).bind { |s|
94
+ ret c + s
95
+ }
96
+ }
97
+ end
98
+ end
99
+ end
100
+
101
+ class Parser
102
+ include Immutable
103
+ include Parsers
104
+
105
+ def initialize(&block)
106
+ @block = block
107
+ end
108
+
109
+ def to_parser
110
+ self
111
+ end
112
+
113
+ def parse(d)
114
+ @block.call(d)
115
+ end
116
+
117
+ def bind(&f2)
118
+ p1 = self
119
+ Parser.new { |d|
120
+ Promise.lazy {
121
+ result = p1.parse(d).force
122
+ if result.succeeded?
123
+ p2 = f2.call(result.value)
124
+ p2.to_parser.parse(result.remainder)
125
+ else
126
+ Promise.eager(NO_PARSE)
127
+ end
128
+ }
129
+ }
130
+ end
131
+
132
+ def /(p2)
133
+ p1 = self
134
+ Parser.new { |d|
135
+ Promise.lazy {
136
+ result = p1.parse(d).force
137
+ if result.succeeded?
138
+ Promise.eager(result)
139
+ else
140
+ p2.to_parser.parse(d)
141
+ end
142
+ }
143
+ }
144
+ end
145
+
146
+ def optional
147
+ self / ret(nil)
148
+ end
149
+
150
+ def zero_or_more
151
+ one_or_more / ret(List.empty)
152
+ end
153
+
154
+ def one_or_more
155
+ bind { |x|
156
+ zero_or_more.bind { |xs|
157
+ ret xs.cons(x)
158
+ }
159
+ }
160
+ end
161
+ end
162
+
163
+ include Parsers
164
+
165
+ def initialize(start_symbol, &block)
166
+ @parsers = {}
167
+ @start_symbol = start_symbol
168
+ instance_exec(&block) if block
169
+ end
170
+
171
+ def parse(str)
172
+ result = Derivs.new(self, str).send(@start_symbol).force
173
+ if !result.succeeded?
174
+ raise ParseError, "parse error"
175
+ end
176
+ result.value
177
+ end
178
+
179
+ def define(sym, parser = yield)
180
+ @parsers[sym] = parser.to_parser
181
+ end
182
+
183
+ def parser(sym)
184
+ @parsers[sym]
185
+ end
186
+
187
+ def method_missing(mid, *args)
188
+ Parser.new(&mid)
189
+ end
190
+ end
191
+ end
data/lib/radd_djur.rb ADDED
@@ -0,0 +1,20 @@
1
+ def with_tailcall_optimization
2
+ if defined?(RubyVM)
3
+ old_option = RubyVM::InstructionSequence.compile_option
4
+ RubyVM::InstructionSequence.compile_option = {
5
+ trace_instruction: false,
6
+ tailcall_optimization: true
7
+ }
8
+ end
9
+ begin
10
+ yield
11
+ ensure
12
+ if defined?(RubyVM)
13
+ RubyVM::InstructionSequence.compile_option = old_option
14
+ end
15
+ end
16
+ end
17
+
18
+ with_tailcall_optimization do
19
+ require "radd_djur/grammar"
20
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: radd_djur
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Shugo Maeda
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-07-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: immutable
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.3.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.3.2
27
+ description:
28
+ email: shugo@ruby-lang.org
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - README.md
34
+ - lib/radd_djur.rb
35
+ - lib/radd_djur/dsl.rb
36
+ - lib/radd_djur/grammar.rb
37
+ homepage: http://github.com/shugo/radd_djur
38
+ licenses: []
39
+ metadata: {}
40
+ post_install_message:
41
+ rdoc_options: []
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ requirements: []
55
+ rubyforge_project:
56
+ rubygems_version: 2.5.1
57
+ signing_key:
58
+ specification_version: 4
59
+ summary: Packrat parser combinator library for Ruby
60
+ test_files: []
61
+ has_rdoc: