kaiseki 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|