kaiseki 0.0.3
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.
- data/lib/additions/proc.rb +7 -0
- data/lib/additions/regexp.rb +7 -0
- data/lib/additions/string.rb +7 -0
- data/lib/additions/symbol.rb +19 -0
- data/lib/grammar/and_predicate.rb +22 -0
- data/lib/grammar/array_result.rb +16 -0
- data/lib/grammar/eof_parslet.rb +32 -0
- data/lib/grammar/grammar.rb +113 -0
- data/lib/grammar/grammar_node.rb +31 -0
- data/lib/grammar/location_tracking.rb +57 -0
- data/lib/grammar/log_node.rb +21 -0
- data/lib/grammar/node.rb +59 -0
- data/lib/grammar/not_predicate.rb +22 -0
- data/lib/grammar/parse_error.rb +21 -0
- data/lib/grammar/parse_logger.rb +27 -0
- data/lib/grammar/parse_result.rb +33 -0
- data/lib/grammar/parslet.rb +29 -0
- data/lib/grammar/parslet_choice.rb +25 -0
- data/lib/grammar/parslet_combination.rb +35 -0
- data/lib/grammar/parslet_combining.rb +57 -0
- data/lib/grammar/parslet_logging.rb +22 -0
- data/lib/grammar/parslet_merger.rb +50 -0
- data/lib/grammar/parslet_omission.rb +20 -0
- data/lib/grammar/parslet_repetition.rb +65 -0
- data/lib/grammar/parslet_sequence.rb +45 -0
- data/lib/grammar/predicate.rb +30 -0
- data/lib/grammar/proc_parslet.rb +18 -0
- data/lib/grammar/regexp_parslet.rb +25 -0
- data/lib/grammar/stream.rb +90 -0
- data/lib/grammar/string_parslet.rb +29 -0
- data/lib/grammar/string_result.rb +16 -0
- data/lib/grammar/symbol_parslet.rb +22 -0
- data/lib/kaiseki.rb +49 -0
- metadata +96 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
class Symbol
|
2
|
+
include Kaiseki::ParsletCombining
|
3
|
+
|
4
|
+
def to_parseable
|
5
|
+
self == :EOF ? Kaiseki::EOFParslet.new : Kaiseki::SymbolParslet.new(self)
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_instance_variable_name
|
9
|
+
self[0] == '@' ? self : :"@#{self}"
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_class_variable_name
|
13
|
+
self[0..1] == '@@' ? self : :"@@#{self}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_class_name
|
17
|
+
self.to_s.split('_').collect {|n| n.capitalize }.join.to_sym
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class AndPredicate < Predicate
|
3
|
+
def initialize parseable
|
4
|
+
super parseable
|
5
|
+
@prefix = 'and'
|
6
|
+
end
|
7
|
+
|
8
|
+
def parse stream, options = {}
|
9
|
+
raise TypeError, "can't convert #{stream.class} into Stream" unless stream.is_a? Stream
|
10
|
+
pos = stream.pos
|
11
|
+
begin
|
12
|
+
@parseable.parse stream, options
|
13
|
+
rescue ParseError
|
14
|
+
stream.rewind pos
|
15
|
+
raise ParseError.new "Predicate not satisfied (expecting `#{@parseable}')",
|
16
|
+
options.merge(:line_end => stream.line, :column_end => stream.column)
|
17
|
+
end
|
18
|
+
stream.rewind pos
|
19
|
+
throw :PredicateSuccess
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class ArrayResult < Array
|
3
|
+
include LocationTracking
|
4
|
+
|
5
|
+
attr_reader :info
|
6
|
+
|
7
|
+
def initialize arg1 = 0, arg2 = nil, info = {}
|
8
|
+
super arg1, arg2
|
9
|
+
self.line_start = info[:line_start] if info.key? :line_start
|
10
|
+
self.column_start = info[:column_start] if info.key? :column_start
|
11
|
+
self.line_end = info[:line_end] if info.key? :line_end
|
12
|
+
self.column_end = info[:column_end] if info.key? :column_end
|
13
|
+
@info = info
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class EOFParslet
|
3
|
+
include ParsletCombining
|
4
|
+
|
5
|
+
def parse stream, options = {}
|
6
|
+
raise TypeError, "can't convert #{stream.class} into Stream" unless stream.is_a? Stream
|
7
|
+
pos = stream.pos
|
8
|
+
char = stream.getc
|
9
|
+
if char
|
10
|
+
stream.rewind pos
|
11
|
+
raise ParseError.new "unexpected character `#{char}' (expected EOF)",
|
12
|
+
options.merge(:line_end => stream.line, :column_end => stream.column)
|
13
|
+
else
|
14
|
+
throw :PredicateSuccess
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
'EOF'
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_parseable
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def eql? other
|
27
|
+
other.is_a? EOFParslet
|
28
|
+
end
|
29
|
+
|
30
|
+
alias :== :eql?
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class Grammar
|
3
|
+
attr_reader :starting_rule, :skipping_rule, :rules, :overrides, :nodes, :actions
|
4
|
+
|
5
|
+
def initialize &block
|
6
|
+
@starting_rule = nil
|
7
|
+
@skipping_rule = nil
|
8
|
+
|
9
|
+
@rules = Hash.new {|hash, key| raise NameError, "rule `#{key}' is not defined" }
|
10
|
+
@overrides = Hash.new {|hash, key| raise NameError, "override `#{key}' is not defined" }
|
11
|
+
@nodes = Hash.new {|hash, key| raise NameError, "node `#{key}' is not defined" }
|
12
|
+
@actions = Hash.new {|hash, key| raise NameError, "action `#{key}' is not defined" }
|
13
|
+
|
14
|
+
@simplify = false
|
15
|
+
|
16
|
+
instance_eval &block if block_given?
|
17
|
+
end
|
18
|
+
|
19
|
+
def starting parseable
|
20
|
+
raise StandardError, "starting rule already defined" if @starting_rule
|
21
|
+
@starting_rule = parseable.to_parseable
|
22
|
+
end
|
23
|
+
|
24
|
+
def skipping parseable
|
25
|
+
raise StandardError, "skipping rule already defined" if @skipping_rule
|
26
|
+
@skipping_rule = parseable.to_parseable
|
27
|
+
end
|
28
|
+
|
29
|
+
def rule symbol, &block
|
30
|
+
raise TypeError, "can't convert #{symbol.class} into Symbol" unless symbol.is_a? Symbol
|
31
|
+
raise StandardError, "rule `#{symbol}' already defined" if @rules.key? symbol
|
32
|
+
GrammarNode.new(symbol, self).instance_eval(&block) if block_given?
|
33
|
+
@rules[symbol] = ProcParslet.new { raise NotImplementedError, "rule `#{symbol}' not yet implemented" } unless @rules.key? symbol
|
34
|
+
end
|
35
|
+
|
36
|
+
def simplify
|
37
|
+
@simplify = true
|
38
|
+
end
|
39
|
+
|
40
|
+
def parse! source, options = {}
|
41
|
+
raise StandardError, "starting rule not defined" unless @starting_rule
|
42
|
+
stream = source.is_a?(Stream) ? source : Stream.new(source)
|
43
|
+
options[:grammar] = self
|
44
|
+
options[:file] = stream.file
|
45
|
+
options[:rule] = @starting_rule.is_a?(SymbolParslet) ? @starting_rule.expected : :root
|
46
|
+
options[:skipping] = @skipping_rule
|
47
|
+
options[:simplify] = @simplify
|
48
|
+
@starting_rule.parse stream, options
|
49
|
+
end
|
50
|
+
|
51
|
+
def parse source, options = {}
|
52
|
+
stream = source.is_a?(Stream) ? source : Stream.new(source)
|
53
|
+
result = ParseResult.new self, stream, options
|
54
|
+
begin
|
55
|
+
result.result = parse! stream, options.merge(:logger => result.logger)
|
56
|
+
rescue ParseError => e
|
57
|
+
result.error = e
|
58
|
+
end
|
59
|
+
result
|
60
|
+
end
|
61
|
+
|
62
|
+
def wrap stream, options = {}
|
63
|
+
raise TypeError, "can't convert #{stream.class} into Stream" unless stream.is_a? Stream
|
64
|
+
raise ArgumentError, "wrapping requires a rule" unless options.key? :rule
|
65
|
+
rule = options[:rule]
|
66
|
+
options.merge! @overrides[rule] if @overrides.key? rule
|
67
|
+
result = @rules[rule].parse stream, options
|
68
|
+
if @nodes.key?(rule) and @actions.key?(rule)
|
69
|
+
node_class = @nodes[rule]
|
70
|
+
if node_class.arity == 1
|
71
|
+
node = node_class.new result
|
72
|
+
else
|
73
|
+
node = node_class.new *result
|
74
|
+
end
|
75
|
+
node.instance_eval &@actions[rule]
|
76
|
+
else
|
77
|
+
result
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class << Grammar
|
83
|
+
def subclass &block
|
84
|
+
if block_given?
|
85
|
+
subclass = Class.new self
|
86
|
+
subclass.bind &block
|
87
|
+
subclass
|
88
|
+
else
|
89
|
+
Class.new self
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def bind &block
|
94
|
+
if self == Grammar
|
95
|
+
raise StandardError, "Grammar rootclass can't be bound"
|
96
|
+
elsif bound?
|
97
|
+
raise StandardError, "Grammar can't be bound multiple times"
|
98
|
+
else
|
99
|
+
self.send :define_method, :initialize do
|
100
|
+
super &block
|
101
|
+
end
|
102
|
+
self.define_singleton_method :bound? do
|
103
|
+
true
|
104
|
+
end
|
105
|
+
end
|
106
|
+
true
|
107
|
+
end
|
108
|
+
|
109
|
+
def bound?
|
110
|
+
false
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class GrammarNode < Node
|
3
|
+
def parse parseable
|
4
|
+
raise StandardError, "rule `#{@name}' already defined" if @grammar.rules.key? @name
|
5
|
+
@grammar.rules[@name] = parseable.to_parseable
|
6
|
+
end
|
7
|
+
|
8
|
+
def override options
|
9
|
+
raise StandardError, "rule `#{@name}' not defined" unless @grammar.rules.key? @name
|
10
|
+
raise StandardError, "override already deinfed for rule `#{@name}'" if @grammar.overrides.key? @name
|
11
|
+
@grammar.overrides[@name] = options
|
12
|
+
end
|
13
|
+
|
14
|
+
def node options = {:params => [:results]}
|
15
|
+
superclass = options.key?(:superclass) ? options[:superclass] : Node
|
16
|
+
raise TypeError, "can't convert #{superclass.class} into Class" unless superclass.is_a? Class
|
17
|
+
raise StandardError, "rule `#{@name}' not defined" unless @grammar.rules.key? @name
|
18
|
+
raise StandardError, "node already defined for rule `#{@name}'" if @grammar.nodes.key? @name
|
19
|
+
node = @grammar.nodes[@name] = superclass.subclass(*options[:params])
|
20
|
+
end
|
21
|
+
|
22
|
+
def action &block
|
23
|
+
raise StandardError, "rule `#{@name}' not defined" unless @grammar.rules.key? @name
|
24
|
+
raise StandardError, "action already defined for rule `#{@name}'" if @grammar.actions.key? @name
|
25
|
+
@grammar.nodes[@name] = node unless @grammar.nodes.key? @name
|
26
|
+
@grammar.actions[@name] = block
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
GrammarNode.bind :name, :grammar
|
31
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
module LocationTracking
|
3
|
+
def line_start
|
4
|
+
@line_start || 0
|
5
|
+
end
|
6
|
+
|
7
|
+
def line_start= number
|
8
|
+
@line_start = number.to_i
|
9
|
+
end
|
10
|
+
|
11
|
+
def column_start
|
12
|
+
@column_start || 0
|
13
|
+
end
|
14
|
+
|
15
|
+
def column_start= number
|
16
|
+
@column_start = number.to_i
|
17
|
+
end
|
18
|
+
|
19
|
+
def start
|
20
|
+
[line_start, column_start]
|
21
|
+
end
|
22
|
+
|
23
|
+
def start= array
|
24
|
+
raise TypeError, "can't convert #{array.class} into Array" unless array.is_a? Array
|
25
|
+
raise ArgumentError, "array must have length 2" unless array.length == 2
|
26
|
+
@line_start = array[0]
|
27
|
+
@column_start = array[1]
|
28
|
+
end
|
29
|
+
|
30
|
+
def line_end
|
31
|
+
@line_end || 0
|
32
|
+
end
|
33
|
+
|
34
|
+
def line_end= number
|
35
|
+
@line_end = number.to_i
|
36
|
+
end
|
37
|
+
|
38
|
+
def column_end
|
39
|
+
@column_end || 0
|
40
|
+
end
|
41
|
+
|
42
|
+
def column_end= number
|
43
|
+
@column_end = number.to_i
|
44
|
+
end
|
45
|
+
|
46
|
+
def end
|
47
|
+
[line_end, column_end]
|
48
|
+
end
|
49
|
+
|
50
|
+
def end= array
|
51
|
+
raise TypeError, "can't convert #{array.class} into Array" unless array.is_a? Array
|
52
|
+
raise ArgumentError, "array must have length 2" unless array.length == 2
|
53
|
+
@line_end = array[0]
|
54
|
+
@column_end = array[1]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class LogNode
|
3
|
+
attr_accessor :result
|
4
|
+
attr_reader :parslet, :children
|
5
|
+
|
6
|
+
def initialize parslet
|
7
|
+
@parslet = parslet
|
8
|
+
@children = []
|
9
|
+
@result = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def add node
|
13
|
+
@children << node
|
14
|
+
end
|
15
|
+
|
16
|
+
def print indent = 0
|
17
|
+
puts " " * indent + "in #{@parslet} got #{@result}"
|
18
|
+
@children.each {|n| n.print indent + 2 }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/grammar/node.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class Node
|
3
|
+
|
4
|
+
end
|
5
|
+
|
6
|
+
class << Node
|
7
|
+
def subclass *parameters
|
8
|
+
if parameters.empty?
|
9
|
+
Class.new self
|
10
|
+
else
|
11
|
+
subclass = Class.new self
|
12
|
+
subclass.bind *parameters
|
13
|
+
subclass
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def bind *parameters
|
18
|
+
if self == Node
|
19
|
+
raise StandardError, "Node rootclass can't be bound"
|
20
|
+
elsif bound?
|
21
|
+
raise StandardError, "Node can't be bound multiple times"
|
22
|
+
else
|
23
|
+
self.send :define_method, :initialize do |*arguments|
|
24
|
+
raise ArgumentError, "wrong number of arguments (#{arguments.length} for #{parameters.length})" unless arguments.length == parameters.length
|
25
|
+
arguments.length.times do |i|
|
26
|
+
instance_variable_set parameters[i].to_instance_variable_name, arguments[i]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
parameters.each do |parameter|
|
30
|
+
self.send :define_method, parameter do
|
31
|
+
instance_variable_get parameter.to_instance_variable_name
|
32
|
+
end
|
33
|
+
end
|
34
|
+
self.define_singleton_method :arity do
|
35
|
+
parameters.length
|
36
|
+
end
|
37
|
+
self.define_singleton_method :parameters do
|
38
|
+
parameters.dup
|
39
|
+
end
|
40
|
+
self.define_singleton_method :bound? do
|
41
|
+
true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
true
|
45
|
+
end
|
46
|
+
|
47
|
+
def arity
|
48
|
+
0
|
49
|
+
end
|
50
|
+
|
51
|
+
def parameters
|
52
|
+
[]
|
53
|
+
end
|
54
|
+
|
55
|
+
def bound?
|
56
|
+
false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class NotPredicate < Predicate
|
3
|
+
def initialize parseable
|
4
|
+
super parseable
|
5
|
+
@prefix = 'not'
|
6
|
+
end
|
7
|
+
|
8
|
+
def parse stream, options = {}
|
9
|
+
raise TypeError, "can't convert #{stream.class} into Stream" unless stream.is_a? Stream
|
10
|
+
pos = stream.pos
|
11
|
+
begin
|
12
|
+
@parseable.parse stream, options
|
13
|
+
rescue ParseError
|
14
|
+
stream.rewind pos
|
15
|
+
throw :PredicateSuccess
|
16
|
+
end
|
17
|
+
stream.rewind pos
|
18
|
+
raise ParseError.new "predicate not satisfied (`#{@parseable}' not allowed)",
|
19
|
+
options.merge(:line_end => stream.line, :column_end => stream.column)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class ParseError < Exception
|
3
|
+
include LocationTracking
|
4
|
+
|
5
|
+
attr_reader :file, :rule
|
6
|
+
|
7
|
+
def initialize message, info = {}
|
8
|
+
super message
|
9
|
+
self.line_start = info[:line_start] if info.key? :line_start
|
10
|
+
self.column_start = info[:column_start] if info.key? :column_start
|
11
|
+
self.line_end = info[:line_end] if info.key? :line_end
|
12
|
+
self.column_end = info[:column_end] if info.key? :column_end
|
13
|
+
@file = info[:file]
|
14
|
+
@rule = info[:rule]
|
15
|
+
end
|
16
|
+
|
17
|
+
def location
|
18
|
+
"from #{@file || 'unknown'}:#{line_end + 1}:#{column_end + 1} in #{@rule || 'unknown'}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class ParseLogger
|
3
|
+
attr_accessor :root
|
4
|
+
attr_reader :stack
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@root = nil
|
8
|
+
@stack = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def push item
|
12
|
+
@stack.push item
|
13
|
+
end
|
14
|
+
|
15
|
+
def pop
|
16
|
+
@stack.pop
|
17
|
+
end
|
18
|
+
|
19
|
+
def add item
|
20
|
+
@stack.last.add item
|
21
|
+
end
|
22
|
+
|
23
|
+
def backtrace
|
24
|
+
@root.print
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class ParseResult
|
3
|
+
attr_accessor :grammar, :stream, :options, :result, :error, :logger
|
4
|
+
|
5
|
+
def initialize grammar, stream, options
|
6
|
+
@grammar = grammar
|
7
|
+
@stream = stream
|
8
|
+
@options = options
|
9
|
+
@result = nil
|
10
|
+
@error = nil
|
11
|
+
@logger = ParseLogger.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def parsed?
|
15
|
+
!@error
|
16
|
+
end
|
17
|
+
|
18
|
+
def error_message
|
19
|
+
"#{@error}\n\t#{@error.location}"
|
20
|
+
end
|
21
|
+
|
22
|
+
alias :msg :error_message
|
23
|
+
|
24
|
+
def reparse options = {}
|
25
|
+
@stream.rewind
|
26
|
+
@grammar.parse @stream, @options.merge(options)
|
27
|
+
end
|
28
|
+
|
29
|
+
def backtrace
|
30
|
+
@logger.backtrace
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class Parslet
|
3
|
+
include ParsletCombining
|
4
|
+
|
5
|
+
attr_reader :expected
|
6
|
+
|
7
|
+
def initialize expected
|
8
|
+
@expected = expected
|
9
|
+
end
|
10
|
+
|
11
|
+
def parse *args
|
12
|
+
raise NotImplementedError
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
"#{@expected}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_parseable
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def eql? other
|
24
|
+
other.is_a?(self.class) and other.expected == @expected
|
25
|
+
end
|
26
|
+
|
27
|
+
alias :== :eql?
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class ParsletChoice < ParsletCombination
|
3
|
+
def initialize *components
|
4
|
+
super *components
|
5
|
+
@delimiter = '|'
|
6
|
+
end
|
7
|
+
|
8
|
+
alias :| :append
|
9
|
+
|
10
|
+
def parse stream, options = {}
|
11
|
+
raise TypeError, "can't convert #{stream.class} into Stream" unless stream.is_a? Stream
|
12
|
+
parsed = ArrayResult.new
|
13
|
+
error = nil
|
14
|
+
@components.each do |parseable|
|
15
|
+
begin
|
16
|
+
return parseable.parse stream, options
|
17
|
+
rescue ParseError => e
|
18
|
+
error = e
|
19
|
+
end
|
20
|
+
end
|
21
|
+
raise ParseError.new "no valid alternatives (#{error})",
|
22
|
+
options.merge(:line_end => stream.line, :column_end => stream.column)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class ParsletCombination
|
3
|
+
include ParsletCombining
|
4
|
+
|
5
|
+
attr_reader :components
|
6
|
+
|
7
|
+
def initialize *components
|
8
|
+
@components = components
|
9
|
+
@delimiter = '--'
|
10
|
+
end
|
11
|
+
|
12
|
+
def append object
|
13
|
+
@components << object.to_parseable
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def parse *args
|
18
|
+
raise NotImplementedError
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
"<#{@components.join " #{@delimiter} "}>"
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_parseable
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
def eql? other
|
30
|
+
other.is_a?(self.class) and other.components == @components
|
31
|
+
end
|
32
|
+
|
33
|
+
alias :== :eql?
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
module ParsletCombining
|
3
|
+
def sequence other
|
4
|
+
ParsletSequence.new self.to_parseable, other.to_parseable
|
5
|
+
end
|
6
|
+
|
7
|
+
alias :& :sequence
|
8
|
+
|
9
|
+
def merge other
|
10
|
+
ParsletMerger.new self.to_parseable, other.to_parseable
|
11
|
+
end
|
12
|
+
|
13
|
+
alias :>> :merge
|
14
|
+
|
15
|
+
def choose other
|
16
|
+
ParsletChoice.new self.to_parseable, other.to_parseable
|
17
|
+
end
|
18
|
+
|
19
|
+
alias :| :choose
|
20
|
+
|
21
|
+
def repeat min, max = nil
|
22
|
+
ParsletRepetition.new self.to_parseable, min, max
|
23
|
+
end
|
24
|
+
|
25
|
+
def optional
|
26
|
+
repeat 0, 1
|
27
|
+
end
|
28
|
+
|
29
|
+
alias :zero_or_one :optional
|
30
|
+
|
31
|
+
def zero_or_more
|
32
|
+
repeat 0
|
33
|
+
end
|
34
|
+
|
35
|
+
def one_or_more
|
36
|
+
repeat 1
|
37
|
+
end
|
38
|
+
|
39
|
+
def and_predicate
|
40
|
+
AndPredicate.new self.to_parseable
|
41
|
+
end
|
42
|
+
|
43
|
+
alias :and? :and_predicate
|
44
|
+
|
45
|
+
def not_predicate
|
46
|
+
NotPredicate.new self.to_parseable
|
47
|
+
end
|
48
|
+
|
49
|
+
alias :not! :not_predicate
|
50
|
+
|
51
|
+
def omission
|
52
|
+
ParsletOmission.new self.to_parseable
|
53
|
+
end
|
54
|
+
|
55
|
+
alias :skip :omission
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
module ParsletLogging
|
3
|
+
def log parse_logger = nil, &block
|
4
|
+
if parse_logger
|
5
|
+
node = LogNode.new self
|
6
|
+
parse_logger.root ? parse_logger.add(node) : parse_logger.root = node
|
7
|
+
parse_logger.push node
|
8
|
+
begin
|
9
|
+
node.result = block.call
|
10
|
+
parse_logger.pop
|
11
|
+
node.result
|
12
|
+
rescue ParseError => e
|
13
|
+
node.result = e
|
14
|
+
parse_logger.pop
|
15
|
+
raise e
|
16
|
+
end
|
17
|
+
else
|
18
|
+
block.call
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class ParsletMerger < ParsletCombination
|
3
|
+
def initialize *components
|
4
|
+
super *components
|
5
|
+
@delimiter = '&'
|
6
|
+
end
|
7
|
+
|
8
|
+
alias :>> :append
|
9
|
+
|
10
|
+
def parse stream, options = {}
|
11
|
+
raise TypeError, "can't convert #{stream.class} into Stream" unless stream.is_a? Stream
|
12
|
+
parsed = ArrayResult.new
|
13
|
+
pos = stream.pos
|
14
|
+
@components.each do |parseable|
|
15
|
+
catch :PredicateSuccess do
|
16
|
+
begin
|
17
|
+
result = parseable.parse stream, options
|
18
|
+
if result.respond_to? :each
|
19
|
+
result.each {|n| parsed << n }
|
20
|
+
else
|
21
|
+
parsed << result
|
22
|
+
end
|
23
|
+
rescue ParseError => e
|
24
|
+
if options[:skipping]
|
25
|
+
begin
|
26
|
+
options[:skipping].parse stream, options.merge(:skipping => nil, :logger => nil)
|
27
|
+
redo
|
28
|
+
rescue ParseError
|
29
|
+
stream.rewind pos
|
30
|
+
raise e
|
31
|
+
end
|
32
|
+
else
|
33
|
+
stream.rewind pos
|
34
|
+
raise e
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
if options[:simplify]
|
40
|
+
if parsed.length == 1
|
41
|
+
parsed.first
|
42
|
+
else
|
43
|
+
parsed
|
44
|
+
end
|
45
|
+
else
|
46
|
+
parsed
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class ParsletOmission < Predicate
|
3
|
+
def initialize parseable
|
4
|
+
super parseable
|
5
|
+
@prefix = 'skip'
|
6
|
+
end
|
7
|
+
|
8
|
+
def parse stream, options = {}
|
9
|
+
raise TypeError, "can't convert #{stream.class} into Stream" unless stream.is_a? Stream
|
10
|
+
pos = stream.pos
|
11
|
+
begin
|
12
|
+
@parseable.parse stream, options
|
13
|
+
rescue ParseError => e
|
14
|
+
stream.rewind pos
|
15
|
+
raise e
|
16
|
+
end
|
17
|
+
throw :PredicateSuccess
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class ParsletRepetition
|
3
|
+
include ParsletCombining
|
4
|
+
|
5
|
+
attr_reader :parseable, :min, :max
|
6
|
+
|
7
|
+
def initialize parseable, min, max = nil
|
8
|
+
@parseable = parseable
|
9
|
+
@min = min
|
10
|
+
@max = max
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse stream, options = {}
|
14
|
+
raise TypeError, "can't convert #{stream.class} into Stream" unless stream.is_a? Stream
|
15
|
+
parsed = ArrayResult.new
|
16
|
+
pos = stream.pos
|
17
|
+
while @max.nil? or parsed.length < @max
|
18
|
+
begin
|
19
|
+
parsed << @parseable.parse(stream, options)
|
20
|
+
rescue ParseError
|
21
|
+
if options[:skipping]
|
22
|
+
begin
|
23
|
+
options[:skipping].parse stream, options.merge(:skipping => nil, :logger => nil)
|
24
|
+
redo
|
25
|
+
rescue ParseError
|
26
|
+
break
|
27
|
+
end
|
28
|
+
else
|
29
|
+
break
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
if parsed.length < @min
|
35
|
+
stream.rewind pos
|
36
|
+
raise ParseError.new "required #{@min} match#{'es' unless @min == 1} but obtained #{parsed.length} (expected `#{@parseable}')",
|
37
|
+
options.merge(:line_end => stream.line, :column_end => stream.column)
|
38
|
+
else
|
39
|
+
if options[:simplify]
|
40
|
+
if @min == 0 and @max == 1
|
41
|
+
parsed.length == 0 ? nil : parsed.first
|
42
|
+
else
|
43
|
+
parsed
|
44
|
+
end
|
45
|
+
else
|
46
|
+
parsed
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_s
|
52
|
+
"repeat(#{@min}, #{@max}): #{@parseable}"
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_parseable
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
def eql? other
|
60
|
+
other.is_a?(ParsletRepetition) and other.parseable == @parseable and other.min == @min and other.max == @max
|
61
|
+
end
|
62
|
+
|
63
|
+
alias :== :eql?
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class ParsletSequence < ParsletCombination
|
3
|
+
def initialize *components
|
4
|
+
super *components
|
5
|
+
@delimiter = '&'
|
6
|
+
end
|
7
|
+
|
8
|
+
alias :& :append
|
9
|
+
|
10
|
+
def parse stream, options = {}
|
11
|
+
raise TypeError, "can't convert #{stream.class} into Stream" unless stream.is_a? Stream
|
12
|
+
parsed = ArrayResult.new
|
13
|
+
pos = stream.pos
|
14
|
+
@components.each do |parseable|
|
15
|
+
catch :PredicateSuccess do
|
16
|
+
begin
|
17
|
+
parsed << parseable.parse(stream, options)
|
18
|
+
rescue ParseError => e
|
19
|
+
if options[:skipping]
|
20
|
+
begin
|
21
|
+
options[:skipping].parse stream, options.merge(:skipping => nil, :logger => nil)
|
22
|
+
redo
|
23
|
+
rescue ParseError
|
24
|
+
stream.rewind pos
|
25
|
+
raise e
|
26
|
+
end
|
27
|
+
else
|
28
|
+
stream.rewind pos
|
29
|
+
raise e
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
if options[:simplify]
|
35
|
+
if parsed.length == 1
|
36
|
+
parsed.first
|
37
|
+
else
|
38
|
+
parsed
|
39
|
+
end
|
40
|
+
else
|
41
|
+
parsed
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class Predicate
|
3
|
+
include ParsletCombining
|
4
|
+
|
5
|
+
attr_reader :parseable
|
6
|
+
|
7
|
+
def initialize parseable
|
8
|
+
@parseable = parseable
|
9
|
+
@prefix = 'predicate'
|
10
|
+
end
|
11
|
+
|
12
|
+
def parse *args
|
13
|
+
raise NotImplementedError
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
"<#{@prefix}:#{@parseable}>"
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_parseable
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def eql? other
|
25
|
+
other.is_a?(self.class) and other.parseable == @parseable
|
26
|
+
end
|
27
|
+
|
28
|
+
alias :== :eql?
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class ProcParslet < Parslet
|
3
|
+
def initialize procedure = nil, &block
|
4
|
+
raise ArgumentError, "can't have both an argument and a block" if block_given? and procedure
|
5
|
+
if block_given?
|
6
|
+
super block
|
7
|
+
else
|
8
|
+
raise TypeError, "can't convert #{procedure.class} into Proc" unless procedure.is_a? Proc
|
9
|
+
super procedure
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse stream, options = {}
|
14
|
+
raise TypeError, "can't convert #{stream.class} into Stream" unless stream.is_a? Stream
|
15
|
+
@expected.call stream, options
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class RegexpParslet < Parslet
|
3
|
+
def initialize regexp
|
4
|
+
raise TypeError, "can't convert #{regexp.class} into Regexp" unless regexp.is_a? Regexp
|
5
|
+
super regexp
|
6
|
+
end
|
7
|
+
|
8
|
+
def parse stream, options = {}
|
9
|
+
raise TypeError, "can't convert #{stream.class} into Stream" unless stream.is_a? Stream
|
10
|
+
parsed = StringResult.new
|
11
|
+
pos = stream.pos
|
12
|
+
match = stream.getc(-1).match /\A#{@expected}/
|
13
|
+
if match
|
14
|
+
stream.rewind pos + match.to_s.length
|
15
|
+
parsed << match.to_s
|
16
|
+
parsed.info[:captures] = match.captures
|
17
|
+
parsed
|
18
|
+
else
|
19
|
+
stream.rewind pos
|
20
|
+
raise ParseError.new "non-matching characters while parsing `#{@expected}'",
|
21
|
+
options.merge(:line_end => stream.line, :column_end => stream.column)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class Stream
|
3
|
+
attr_reader :file
|
4
|
+
|
5
|
+
def initialize source
|
6
|
+
if source.is_a? String
|
7
|
+
@file = nil
|
8
|
+
@string = source.dup
|
9
|
+
elsif source.is_a? File
|
10
|
+
@file = source.path
|
11
|
+
@string = ''
|
12
|
+
source.each_char {|c| @string << c }
|
13
|
+
else
|
14
|
+
raise TypeError, "can't convert #{source.class} into Stream"
|
15
|
+
end
|
16
|
+
@pos = 0
|
17
|
+
@newlines = []
|
18
|
+
start = 0
|
19
|
+
@string.length.times do |i|
|
20
|
+
if @string[i] == "\n"
|
21
|
+
@newlines << [start, i]
|
22
|
+
start = i + 1
|
23
|
+
end
|
24
|
+
end
|
25
|
+
@newlines << [start, @string.length]
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
@string.dup
|
30
|
+
end
|
31
|
+
|
32
|
+
def length
|
33
|
+
@string.length
|
34
|
+
end
|
35
|
+
|
36
|
+
def pos
|
37
|
+
@pos
|
38
|
+
end
|
39
|
+
|
40
|
+
def line
|
41
|
+
bsearch @pos, 0, @newlines.length
|
42
|
+
end
|
43
|
+
|
44
|
+
def column
|
45
|
+
@pos - @newlines[self.line].first
|
46
|
+
end
|
47
|
+
|
48
|
+
def getc num = 0
|
49
|
+
if num == 0
|
50
|
+
char = @string[@pos]
|
51
|
+
if char
|
52
|
+
@pos += 1
|
53
|
+
char
|
54
|
+
end
|
55
|
+
elsif num > 0
|
56
|
+
string = @string[@pos..(@pos + num - 1)]
|
57
|
+
@pos += string.length
|
58
|
+
string
|
59
|
+
else
|
60
|
+
string = @string[@pos..num]
|
61
|
+
@pos += string.length
|
62
|
+
string
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def rewind pos = 0
|
67
|
+
if pos < 0
|
68
|
+
pos = @string.length + pos + 1
|
69
|
+
@pos = pos < 0 ? 0 : pos
|
70
|
+
elsif pos > @string.length
|
71
|
+
@pos = @string.length
|
72
|
+
else
|
73
|
+
@pos = pos
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
def bsearch value, low, high
|
79
|
+
return nil if high < low
|
80
|
+
mid = low + (high - low) / 2
|
81
|
+
if value < @newlines[mid].first
|
82
|
+
bsearch value, low, mid - 1
|
83
|
+
elsif value > @newlines[mid].last
|
84
|
+
bsearch value, mid + 1, high
|
85
|
+
else
|
86
|
+
mid
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class StringParslet < Parslet
|
3
|
+
def initialize string
|
4
|
+
raise TypeError, "can't convert #{string.class} into String" unless string.is_a? String
|
5
|
+
super string
|
6
|
+
end
|
7
|
+
|
8
|
+
def parse stream, options = {}
|
9
|
+
raise TypeError, "can't convert #{stream.class} into Stream" unless stream.is_a? Stream
|
10
|
+
parsed = StringResult.new
|
11
|
+
pos = stream.pos
|
12
|
+
@expected.each_char do |char|
|
13
|
+
actual = stream.getc
|
14
|
+
if actual.nil?
|
15
|
+
stream.rewind pos
|
16
|
+
raise ParseError.new "unexpected end-of-string (expected `#{char}') while parsing `#{@expected}'",
|
17
|
+
options.merge(:line_end => stream.line, :column_end => stream.column)
|
18
|
+
elsif actual != char
|
19
|
+
stream.rewind pos
|
20
|
+
raise ParseError.new "unexpected character `#{actual}' (expected `#{char}') while parsing `#{@expected}'",
|
21
|
+
options.merge(:line_end => stream.line, :column_end => stream.column)
|
22
|
+
else
|
23
|
+
parsed << actual
|
24
|
+
end
|
25
|
+
end
|
26
|
+
parsed
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class StringResult < String
|
3
|
+
include LocationTracking
|
4
|
+
|
5
|
+
attr_reader :info
|
6
|
+
|
7
|
+
def initialize string = '', info = {}
|
8
|
+
super string
|
9
|
+
self.line_start = info[:line_start] if info.key? :line_start
|
10
|
+
self.column_start = info[:column_start] if info.key? :column_start
|
11
|
+
self.line_end = info[:line_end] if info.key? :line_end
|
12
|
+
self.column_end = info[:column_end] if info.key? :column_end
|
13
|
+
@info = info
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class SymbolParslet < Parslet
|
3
|
+
include ParsletLogging
|
4
|
+
|
5
|
+
def initialize symbol
|
6
|
+
raise TypeError, "can't convert #{symbol.class} into Symbol" unless symbol.is_a? Symbol
|
7
|
+
super symbol
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse stream, options = {}
|
11
|
+
raise TypeError, "can't convert #{stream.class} into Stream" unless stream.is_a? Stream
|
12
|
+
raise ArgumentError, "parsing requires a grammar" unless options.key? :grammar
|
13
|
+
log options[:logger] do
|
14
|
+
options[:grammar].wrap stream, options.merge(:rule => @expected)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
":#{@expected}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/kaiseki.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module Kaiseki
|
4
|
+
VERSION = '0.0.3'
|
5
|
+
end
|
6
|
+
|
7
|
+
dir_path = Pathname.new(__FILE__).realpath.dirname
|
8
|
+
|
9
|
+
[
|
10
|
+
'grammar/parslet_combining',
|
11
|
+
'grammar/parslet_logging',
|
12
|
+
'grammar/location_tracking',
|
13
|
+
'grammar/parse_error',
|
14
|
+
'grammar/parse_result',
|
15
|
+
'grammar/string_result',
|
16
|
+
'grammar/array_result',
|
17
|
+
|
18
|
+
'grammar/stream',
|
19
|
+
'grammar/parslet',
|
20
|
+
'grammar/proc_parslet',
|
21
|
+
'grammar/regexp_parslet',
|
22
|
+
'grammar/string_parslet',
|
23
|
+
'grammar/symbol_parslet',
|
24
|
+
'grammar/eof_parslet',
|
25
|
+
|
26
|
+
'grammar/parslet_combination',
|
27
|
+
'grammar/parslet_sequence',
|
28
|
+
'grammar/parslet_merger',
|
29
|
+
'grammar/parslet_choice',
|
30
|
+
'grammar/parslet_repetition',
|
31
|
+
|
32
|
+
'grammar/predicate',
|
33
|
+
'grammar/and_predicate',
|
34
|
+
'grammar/not_predicate',
|
35
|
+
'grammar/parslet_omission',
|
36
|
+
|
37
|
+
'grammar/grammar',
|
38
|
+
'grammar/parse_logger',
|
39
|
+
'grammar/node',
|
40
|
+
'grammar/grammar_node',
|
41
|
+
'grammar/log_node',
|
42
|
+
|
43
|
+
'additions/proc',
|
44
|
+
'additions/regexp',
|
45
|
+
'additions/string',
|
46
|
+
'additions/symbol',
|
47
|
+
].each do |path|
|
48
|
+
require dir_path + path
|
49
|
+
end
|
metadata
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: kaiseki
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 3
|
9
|
+
version: 0.0.3
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- William Hamilton-Levi
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-11-23 00:00:00 -05:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: A parsing expression grammar generator written in Ruby.
|
22
|
+
email: whamilt1@swarthmore.edu
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files: []
|
28
|
+
|
29
|
+
files:
|
30
|
+
- lib/kaiseki.rb
|
31
|
+
- lib/additions/symbol.rb
|
32
|
+
- lib/additions/string.rb
|
33
|
+
- lib/additions/regexp.rb
|
34
|
+
- lib/additions/proc.rb
|
35
|
+
- lib/grammar/array_result.rb
|
36
|
+
- lib/grammar/symbol_parslet.rb
|
37
|
+
- lib/grammar/string_parslet.rb
|
38
|
+
- lib/grammar/eof_parslet.rb
|
39
|
+
- lib/grammar/string_result.rb
|
40
|
+
- lib/grammar/grammar_node.rb
|
41
|
+
- lib/grammar/node.rb
|
42
|
+
- lib/grammar/parslet_omission.rb
|
43
|
+
- lib/grammar/parslet.rb
|
44
|
+
- lib/grammar/regexp_parslet.rb
|
45
|
+
- lib/grammar/predicate.rb
|
46
|
+
- lib/grammar/stream.rb
|
47
|
+
- lib/grammar/parslet_sequence.rb
|
48
|
+
- lib/grammar/parslet_merger.rb
|
49
|
+
- lib/grammar/not_predicate.rb
|
50
|
+
- lib/grammar/parslet_combination.rb
|
51
|
+
- lib/grammar/parslet_repetition.rb
|
52
|
+
- lib/grammar/parse_result.rb
|
53
|
+
- lib/grammar/parslet_logging.rb
|
54
|
+
- lib/grammar/parse_logger.rb
|
55
|
+
- lib/grammar/grammar.rb
|
56
|
+
- lib/grammar/log_node.rb
|
57
|
+
- lib/grammar/and_predicate.rb
|
58
|
+
- lib/grammar/parslet_choice.rb
|
59
|
+
- lib/grammar/parslet_combining.rb
|
60
|
+
- lib/grammar/location_tracking.rb
|
61
|
+
- lib/grammar/proc_parslet.rb
|
62
|
+
- lib/grammar/parse_error.rb
|
63
|
+
has_rdoc: true
|
64
|
+
homepage: http://github.com/phi2dao/Kaiseki
|
65
|
+
licenses: []
|
66
|
+
|
67
|
+
post_install_message:
|
68
|
+
rdoc_options: []
|
69
|
+
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
segments:
|
78
|
+
- 0
|
79
|
+
version: "0"
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
segments:
|
86
|
+
- 0
|
87
|
+
version: "0"
|
88
|
+
requirements: []
|
89
|
+
|
90
|
+
rubyforge_project:
|
91
|
+
rubygems_version: 1.3.7
|
92
|
+
signing_key:
|
93
|
+
specification_version: 3
|
94
|
+
summary: A parsing expression grammar generator written in Ruby.
|
95
|
+
test_files: []
|
96
|
+
|