chomsky 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/chomsky/action.rb +15 -0
- data/lib/chomsky/grammar.rb +20 -0
- data/lib/chomsky/parser.rb +29 -0
- data/lib/chomsky/parser_generator.rb +35 -0
- data/lib/chomsky/parser_generators/and.rb +25 -0
- data/lib/chomsky/parser_generators/backreference.rb +19 -0
- data/lib/chomsky/parser_generators/capture.rb +18 -0
- data/lib/chomsky/parser_generators/combinators.rb +83 -0
- data/lib/chomsky/parser_generators/compose.rb +25 -0
- data/lib/chomsky/parser_generators/not.rb +16 -0
- data/lib/chomsky/parser_generators/or.rb +25 -0
- data/lib/chomsky/parser_generators/peek.rb +16 -0
- data/lib/chomsky/parser_generators/perhaps.rb +12 -0
- data/lib/chomsky/parser_generators/repeat.rb +24 -0
- data/lib/chomsky/parser_generators/skip.rb +17 -0
- data/lib/chomsky/parser_generators/some.rb +21 -0
- data/lib/chomsky/parsers/anything.rb +21 -0
- data/lib/chomsky/parsers/basic_parsers.rb +36 -0
- data/lib/chomsky/parsers/blank.rb +11 -0
- data/lib/chomsky/parsers/literal.rb +19 -0
- data/lib/chomsky/parsers/nothing.rb +15 -0
- data/lib/chomsky/parsers/regexp.rb +19 -0
- data/lib/chomsky/rule.rb +25 -0
- data/lib/chomsky.rb +7 -0
- metadata +72 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'chomsky'
|
2
|
+
|
3
|
+
module Chomsky
|
4
|
+
class Grammar
|
5
|
+
include Parser::BasicParsers
|
6
|
+
include ParserGenerator::Combinators
|
7
|
+
|
8
|
+
def self.rule name, &pg
|
9
|
+
define_method(name) { Rule.new(self, pg) }
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.action name, &block
|
13
|
+
define_method(name) { Action.new(self, block) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'chomsky'
|
2
|
+
|
3
|
+
module Chomsky
|
4
|
+
class Parser
|
5
|
+
autoload :Anything, "chomsky/parsers/anything"
|
6
|
+
autoload :BasicParsers, "chomsky/parsers/basic_parsers"
|
7
|
+
autoload :Blank, "chomsky/parsers/blank"
|
8
|
+
autoload :Literal, "chomsky/parsers/literal"
|
9
|
+
autoload :Nothing, "chomsky/parsers/nothing"
|
10
|
+
autoload :Regexp, "chomsky/parsers/regexp"
|
11
|
+
|
12
|
+
include ParserGenerator::Combinators
|
13
|
+
|
14
|
+
def self.call *args
|
15
|
+
new(*args)
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
end
|
20
|
+
|
21
|
+
def call string
|
22
|
+
[nil, string]
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_pg
|
26
|
+
self
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'chomsky/parser_generators/combinators'
|
2
|
+
|
3
|
+
module Chomsky
|
4
|
+
class ParserGenerator
|
5
|
+
autoload :And, "chomsky/parser_generators/and"
|
6
|
+
autoload :Compose, "chomsky/parser_generators/compose"
|
7
|
+
autoload :Repeat, "chomsky/parser_generators/repeat"
|
8
|
+
autoload :Not, "chomsky/parser_generators/not"
|
9
|
+
autoload :Or, "chomsky/parser_generators/or"
|
10
|
+
autoload :Peek, "chomsky/parser_generators/peek"
|
11
|
+
autoload :Perhaps, "chomsky/parser_generators/perhaps"
|
12
|
+
autoload :Skip, "chomsky/parser_generators/skip"
|
13
|
+
autoload :Some, "chomsky/parser_generators/some"
|
14
|
+
autoload :Capture, "chomsky/parser_generators/capture"
|
15
|
+
autoload :Backreference, "chomsky/parser_generators/backreference"
|
16
|
+
|
17
|
+
include Chomsky::ParserGenerator::Combinators
|
18
|
+
|
19
|
+
def self.call *args
|
20
|
+
new(*args)
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize parser
|
24
|
+
@parser = parser
|
25
|
+
end
|
26
|
+
|
27
|
+
def call string
|
28
|
+
@parser.call(string)
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_pg
|
32
|
+
self
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'chomsky/parser_generator'
|
2
|
+
|
3
|
+
module Chomsky
|
4
|
+
class ParserGenerator
|
5
|
+
class And < ParserGenerator
|
6
|
+
def initialize left, right
|
7
|
+
@left, @right = left, right
|
8
|
+
end
|
9
|
+
|
10
|
+
def call string
|
11
|
+
head, rest = @left.(string)
|
12
|
+
if head
|
13
|
+
more, rest = @right.(rest)
|
14
|
+
if more
|
15
|
+
[head + more, rest]
|
16
|
+
else
|
17
|
+
[nil, string]
|
18
|
+
end
|
19
|
+
else
|
20
|
+
[nil, string]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'chomsky'
|
2
|
+
|
3
|
+
module Chomsky
|
4
|
+
class ParserGenerator
|
5
|
+
class Backreference < ParserGenerator
|
6
|
+
def initialize capture
|
7
|
+
@capture = capture
|
8
|
+
end
|
9
|
+
|
10
|
+
def call string
|
11
|
+
if parser = @capture.parser
|
12
|
+
parser.(string)
|
13
|
+
else
|
14
|
+
[nil, string]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'chomsky'
|
2
|
+
|
3
|
+
module Chomsky
|
4
|
+
class ParserGenerator
|
5
|
+
class Capture < ParserGenerator
|
6
|
+
attr_reader :parser
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@parser = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def call string
|
13
|
+
@parser = Parser::Literal.(string)
|
14
|
+
[string, ""]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'chomsky'
|
2
|
+
|
3
|
+
module Chomsky
|
4
|
+
class ParserGenerator
|
5
|
+
module Combinators
|
6
|
+
def !
|
7
|
+
Not.(self.to_pg)
|
8
|
+
end
|
9
|
+
|
10
|
+
def _?
|
11
|
+
Perhaps.(self.to_pg)
|
12
|
+
end
|
13
|
+
|
14
|
+
def & other
|
15
|
+
And.(self.to_pg, other.to_pg)
|
16
|
+
end
|
17
|
+
|
18
|
+
def | other
|
19
|
+
Or.(self.to_pg, other.to_pg)
|
20
|
+
end
|
21
|
+
|
22
|
+
def < other
|
23
|
+
Skip.(self.to_pg) & other.to_pg
|
24
|
+
end
|
25
|
+
|
26
|
+
def > other
|
27
|
+
self.to_pg & Skip.(other.to_pg)
|
28
|
+
end
|
29
|
+
|
30
|
+
def % other
|
31
|
+
self.to_pg & Peek.(other.to_pg)
|
32
|
+
end
|
33
|
+
|
34
|
+
def - other
|
35
|
+
self.to_pg >> !(other.to_pg)
|
36
|
+
end
|
37
|
+
|
38
|
+
def +
|
39
|
+
Some.(self.to_pg)
|
40
|
+
end
|
41
|
+
|
42
|
+
def *
|
43
|
+
self.+()._?
|
44
|
+
end
|
45
|
+
|
46
|
+
def [] min, max = nil
|
47
|
+
if max
|
48
|
+
p = Repeat.(self._?, max)
|
49
|
+
min ? Repeat.(self.to_pg, min) & p : p
|
50
|
+
else
|
51
|
+
case min
|
52
|
+
when 0
|
53
|
+
self.*()
|
54
|
+
when 1
|
55
|
+
self.+()
|
56
|
+
else
|
57
|
+
Repeat.(self.to_pg, min) & self._?.*()
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def >> other
|
63
|
+
Compose.(self.to_pg, other.to_pg)
|
64
|
+
end
|
65
|
+
|
66
|
+
def capture name
|
67
|
+
captures[name] = Capture.new
|
68
|
+
end
|
69
|
+
alias_method :cap, :capture
|
70
|
+
|
71
|
+
def reference name
|
72
|
+
Backreference.new(captures[name])
|
73
|
+
end
|
74
|
+
alias_method :ref, :reference
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def captures
|
79
|
+
@captures ||= {}
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'chomsky/parser_generator'
|
2
|
+
|
3
|
+
module Chomsky
|
4
|
+
class ParserGenerator
|
5
|
+
class Compose < ParserGenerator
|
6
|
+
def initialize left, right
|
7
|
+
@left, @right = left, right
|
8
|
+
end
|
9
|
+
|
10
|
+
def call string
|
11
|
+
head, rest = @left.(string)
|
12
|
+
if head
|
13
|
+
more, _ = @right.(head)
|
14
|
+
if more
|
15
|
+
[more, rest]
|
16
|
+
else
|
17
|
+
[nil, string]
|
18
|
+
end
|
19
|
+
else
|
20
|
+
[nil, string]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'chomsky/parser_generator'
|
2
|
+
|
3
|
+
module Chomsky
|
4
|
+
class ParserGenerator
|
5
|
+
class Or < ParserGenerator
|
6
|
+
def initialize left, right
|
7
|
+
@left, @right = left, right
|
8
|
+
end
|
9
|
+
|
10
|
+
def call string
|
11
|
+
head, rest = @left.(string)
|
12
|
+
if head
|
13
|
+
[head, rest]
|
14
|
+
else
|
15
|
+
more, rest = @right.(string)
|
16
|
+
if more
|
17
|
+
[more, rest]
|
18
|
+
else
|
19
|
+
[nil, string]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'chomsky/parser_generator'
|
2
|
+
|
3
|
+
module Chomsky
|
4
|
+
class ParserGenerator
|
5
|
+
class Repeat < ParserGenerator
|
6
|
+
def initialize parser, n
|
7
|
+
super(parser)
|
8
|
+
@n = n
|
9
|
+
end
|
10
|
+
|
11
|
+
def call string
|
12
|
+
head, rest = "", string
|
13
|
+
@n.times do
|
14
|
+
more, rest = @parser.(rest)
|
15
|
+
if more
|
16
|
+
head += more
|
17
|
+
else
|
18
|
+
return [nil, string]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'chomsky/parser_generator'
|
2
|
+
|
3
|
+
module Chomsky
|
4
|
+
class ParserGenerator
|
5
|
+
class Some < ParserGenerator
|
6
|
+
def call string
|
7
|
+
head, rest = @parser.(string)
|
8
|
+
if head
|
9
|
+
more = ""
|
10
|
+
until more.nil?
|
11
|
+
more, rest = @parser.(rest)
|
12
|
+
head += more if more
|
13
|
+
end
|
14
|
+
[head, rest]
|
15
|
+
else
|
16
|
+
[nil, string]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'chomsky'
|
2
|
+
|
3
|
+
module Chomsky
|
4
|
+
class Parser
|
5
|
+
class Anything < Parser
|
6
|
+
attr_reader :length
|
7
|
+
|
8
|
+
def initialize length = 1
|
9
|
+
@length = length
|
10
|
+
end
|
11
|
+
|
12
|
+
def call string
|
13
|
+
if string.length < @length
|
14
|
+
[nil, string]
|
15
|
+
else
|
16
|
+
[string[0,@length], string[@length..-1]]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'chomsky/parser'
|
2
|
+
require 'chomsky/parser_generators/perhaps'
|
3
|
+
|
4
|
+
module Chomsky
|
5
|
+
class Parser
|
6
|
+
module BasicParsers
|
7
|
+
# Any single character
|
8
|
+
def _
|
9
|
+
Anything.()
|
10
|
+
end
|
11
|
+
|
12
|
+
# Only matches an empty string
|
13
|
+
def eos
|
14
|
+
Nothing.()
|
15
|
+
end
|
16
|
+
|
17
|
+
# Matches one or more whitespace characters
|
18
|
+
def ___
|
19
|
+
Blank.()
|
20
|
+
end
|
21
|
+
|
22
|
+
# optional whitespace
|
23
|
+
def ___?
|
24
|
+
ParserGenerator::Perhaps.(Blank.())
|
25
|
+
end
|
26
|
+
|
27
|
+
def ` string
|
28
|
+
Literal.(string)
|
29
|
+
end
|
30
|
+
|
31
|
+
def r regexp
|
32
|
+
Parser::Regexp.(regexp)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'chomsky/parser'
|
2
|
+
|
3
|
+
module Chomsky
|
4
|
+
class Parser
|
5
|
+
class Literal < Parser
|
6
|
+
def initialize string
|
7
|
+
@value = string
|
8
|
+
end
|
9
|
+
|
10
|
+
def call string
|
11
|
+
if string.start_with?(@value)
|
12
|
+
[@value, string[@value.length..-1]]
|
13
|
+
else
|
14
|
+
[nil, string]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'chomsky/parser'
|
2
|
+
|
3
|
+
module Chomsky
|
4
|
+
class Parser
|
5
|
+
class Regexp < Parser
|
6
|
+
def initialize pattern
|
7
|
+
@pattern = ::Regexp.new("\\A" + pattern.source)
|
8
|
+
end
|
9
|
+
|
10
|
+
def call string
|
11
|
+
if mdata = @pattern.match(string)
|
12
|
+
[mdata.to_s, string[mdata.to_s.length..-1]]
|
13
|
+
else
|
14
|
+
[nil, string]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/chomsky/rule.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'chomsky/parser_generator'
|
2
|
+
|
3
|
+
module Chomsky
|
4
|
+
class Rule < ParserGenerator
|
5
|
+
attr_reader :name
|
6
|
+
|
7
|
+
def initialize grammar, pg
|
8
|
+
@grammar = grammar
|
9
|
+
@pg = pg
|
10
|
+
end
|
11
|
+
|
12
|
+
def call string
|
13
|
+
if parser = @grammar.instance_exec(&@pg)
|
14
|
+
tok, rest = parser.(string)
|
15
|
+
if tok
|
16
|
+
[tok, rest]
|
17
|
+
else
|
18
|
+
[nil, string]
|
19
|
+
end
|
20
|
+
else
|
21
|
+
[nil, string]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/chomsky.rb
ADDED
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: chomsky
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Sander Hartlage
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-04-16 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Chomsky generates parsing expression grammars with a nice pure-Ruby DSL,
|
15
|
+
eliminating the need for secondary grammar definition files or out-of-band compilation,
|
16
|
+
and allowing a grammar's rules to grow dynamically or be manipulated as easy-to-understand
|
17
|
+
Ruby objects.
|
18
|
+
email: sander.hartlage@gmail.com
|
19
|
+
executables: []
|
20
|
+
extensions: []
|
21
|
+
extra_rdoc_files: []
|
22
|
+
files:
|
23
|
+
- lib/chomsky/action.rb
|
24
|
+
- lib/chomsky/grammar.rb
|
25
|
+
- lib/chomsky/parser.rb
|
26
|
+
- lib/chomsky/parser_generator.rb
|
27
|
+
- lib/chomsky/parser_generators/and.rb
|
28
|
+
- lib/chomsky/parser_generators/backreference.rb
|
29
|
+
- lib/chomsky/parser_generators/capture.rb
|
30
|
+
- lib/chomsky/parser_generators/combinators.rb
|
31
|
+
- lib/chomsky/parser_generators/compose.rb
|
32
|
+
- lib/chomsky/parser_generators/not.rb
|
33
|
+
- lib/chomsky/parser_generators/or.rb
|
34
|
+
- lib/chomsky/parser_generators/peek.rb
|
35
|
+
- lib/chomsky/parser_generators/perhaps.rb
|
36
|
+
- lib/chomsky/parser_generators/repeat.rb
|
37
|
+
- lib/chomsky/parser_generators/skip.rb
|
38
|
+
- lib/chomsky/parser_generators/some.rb
|
39
|
+
- lib/chomsky/parsers/anything.rb
|
40
|
+
- lib/chomsky/parsers/basic_parsers.rb
|
41
|
+
- lib/chomsky/parsers/blank.rb
|
42
|
+
- lib/chomsky/parsers/literal.rb
|
43
|
+
- lib/chomsky/parsers/nothing.rb
|
44
|
+
- lib/chomsky/parsers/regexp.rb
|
45
|
+
- lib/chomsky/rule.rb
|
46
|
+
- lib/chomsky.rb
|
47
|
+
homepage: http://github.com/sander6/chomsky
|
48
|
+
licenses: []
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options: []
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ! '>='
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ! '>='
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
requirements: []
|
66
|
+
rubyforge_project:
|
67
|
+
rubygems_version: 1.8.23
|
68
|
+
signing_key:
|
69
|
+
specification_version: 3
|
70
|
+
summary: Pure-Ruby parsing expression grammar generator
|
71
|
+
test_files: []
|
72
|
+
has_rdoc:
|