kaiseki 0.0.3

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