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.
@@ -0,0 +1,7 @@
1
+ class Proc
2
+ include Kaiseki::ParsletCombining
3
+
4
+ def to_parseable
5
+ Kaiseki::ProcParslet.new self
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ class Regexp
2
+ include Kaiseki::ParsletCombining
3
+
4
+ def to_parseable
5
+ Kaiseki::RegexpParslet.new self
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ class String
2
+ include Kaiseki::ParsletCombining
3
+
4
+ def to_parseable
5
+ Kaiseki::StringParslet.new self
6
+ end
7
+ end
@@ -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
@@ -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
+