kaiseki 0.0.3 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +0 -0
- data/lib/action.rb +8 -0
- data/lib/grammar.rb +88 -0
- data/lib/kaiseki.rb +54 -48
- data/lib/mod_file.rb +5 -0
- data/lib/mod_kernel.rb +11 -0
- data/lib/mod_object.rb +11 -0
- data/lib/mod_proc.rb +7 -0
- data/lib/mod_regexp.rb +7 -0
- data/lib/mod_string.rb +11 -0
- data/lib/mod_symbol.rb +27 -0
- data/lib/node.rb +78 -0
- data/lib/parse_error.rb +16 -0
- data/lib/parse_result.rb +21 -0
- data/lib/parseable.rb +67 -0
- data/lib/{grammar/parslet.rb → parser_basic.rb} +7 -12
- data/lib/parser_choice.rb +24 -0
- data/lib/parser_eof.rb +27 -0
- data/lib/parser_multi.rb +27 -0
- data/lib/parser_package.rb +11 -0
- data/lib/parser_regexp.rb +19 -0
- data/lib/parser_repeat.rb +68 -0
- data/lib/parser_sequence.rb +41 -0
- data/lib/parser_string.rb +18 -0
- data/lib/parser_symbol.rb +16 -0
- data/lib/predicate_and.rb +19 -0
- data/lib/predicate_not.rb +19 -0
- data/lib/predicate_skip.rb +19 -0
- data/lib/result_cast.rb +33 -0
- data/lib/result_filter.rb +36 -0
- data/lib/result_merge.rb +20 -0
- data/lib/result_override.rb +20 -0
- data/lib/rule.rb +88 -0
- data/lib/stream.rb +98 -0
- data/lib/var_get.rb +40 -0
- data/lib/var_insert.rb +19 -0
- data/lib/var_set.rb +24 -0
- metadata +45 -40
- data/lib/additions/proc.rb +0 -7
- data/lib/additions/regexp.rb +0 -7
- data/lib/additions/string.rb +0 -7
- data/lib/additions/symbol.rb +0 -19
- data/lib/grammar/and_predicate.rb +0 -22
- data/lib/grammar/array_result.rb +0 -16
- data/lib/grammar/eof_parslet.rb +0 -32
- data/lib/grammar/grammar.rb +0 -113
- data/lib/grammar/grammar_node.rb +0 -31
- data/lib/grammar/location_tracking.rb +0 -57
- data/lib/grammar/log_node.rb +0 -21
- data/lib/grammar/node.rb +0 -59
- data/lib/grammar/not_predicate.rb +0 -22
- data/lib/grammar/parse_error.rb +0 -21
- data/lib/grammar/parse_logger.rb +0 -27
- data/lib/grammar/parse_result.rb +0 -33
- data/lib/grammar/parslet_choice.rb +0 -25
- data/lib/grammar/parslet_combination.rb +0 -35
- data/lib/grammar/parslet_combining.rb +0 -57
- data/lib/grammar/parslet_logging.rb +0 -22
- data/lib/grammar/parslet_merger.rb +0 -50
- data/lib/grammar/parslet_omission.rb +0 -20
- data/lib/grammar/parslet_repetition.rb +0 -65
- data/lib/grammar/parslet_sequence.rb +0 -45
- data/lib/grammar/predicate.rb +0 -30
- data/lib/grammar/proc_parslet.rb +0 -18
- data/lib/grammar/regexp_parslet.rb +0 -25
- data/lib/grammar/stream.rb +0 -90
- data/lib/grammar/string_parslet.rb +0 -29
- data/lib/grammar/string_result.rb +0 -16
- data/lib/grammar/symbol_parslet.rb +0 -22
data/README
ADDED
File without changes
|
data/lib/action.rb
ADDED
data/lib/grammar.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class Grammar
|
3
|
+
attr_reader :rules, :nodes
|
4
|
+
attr_accessor :starting_rule, :skipping_rule, :simplify
|
5
|
+
|
6
|
+
def initialize &block
|
7
|
+
@rules = Hash.new {|hash, key| raise "rule #{key.inspect} undefined" }
|
8
|
+
@nodes = Hash.new {|hash, key| raise "node #{key.inspect} undefined" }
|
9
|
+
@starting_rule = nil
|
10
|
+
@skipping_rule = nil
|
11
|
+
@simplify = true
|
12
|
+
|
13
|
+
instance_eval &block if block_given?
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse stream, options = {}
|
17
|
+
ParseResult.new do
|
18
|
+
parse! stream.to_stream, options
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse! stream, options = {}
|
23
|
+
stream.must_be Stream
|
24
|
+
stream.lock do
|
25
|
+
default_options = {
|
26
|
+
:grammar => self,
|
27
|
+
:rule => 'main',
|
28
|
+
:skipping => @skipping_rule,
|
29
|
+
:simplify => @simplify,
|
30
|
+
:global => {},
|
31
|
+
}
|
32
|
+
if @starting_rule
|
33
|
+
@starting_rule.parse stream, default_options.merge(options)
|
34
|
+
else
|
35
|
+
raise "starting rule undefined"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def starting parseable
|
41
|
+
raise "starting rule already defined" if @starting_rule
|
42
|
+
@starting_rule = parseable
|
43
|
+
end
|
44
|
+
|
45
|
+
def skipping parseable
|
46
|
+
raise "skipping rule already defined" if @skipping_rule
|
47
|
+
@skipping_rule = parseable
|
48
|
+
end
|
49
|
+
|
50
|
+
def simplify bool = true
|
51
|
+
@simplify = bool
|
52
|
+
end
|
53
|
+
|
54
|
+
def rule name, parseable = nil, &block
|
55
|
+
if @rules.key? name
|
56
|
+
raise "rule #{name.inspect} already defined"
|
57
|
+
else
|
58
|
+
if parseable and block_given?
|
59
|
+
raise ArgumentError, "wrong number of arguments; the second argument is mutually exclusive with a block"
|
60
|
+
elsif parseable
|
61
|
+
@rules[name] = parseable.to_parseable
|
62
|
+
elsif block_given?
|
63
|
+
@rules[name] = Rule.new(name, self, &block).parseable
|
64
|
+
else
|
65
|
+
@rules[name] = nil
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def action name, &block
|
71
|
+
if @rules.key? name
|
72
|
+
raise "rule #{name.inspect} already defined"
|
73
|
+
else
|
74
|
+
@rules[name] = block.to_parseable
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def node name, args, options = {}
|
79
|
+
args.must_be Array
|
80
|
+
if @nodes.key? name
|
81
|
+
raise "node #{name.inspect} already defined"
|
82
|
+
else
|
83
|
+
parent = options[:class] || Node
|
84
|
+
@nodes[name] = parent.subclass args, options
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/kaiseki.rb
CHANGED
@@ -1,49 +1,55 @@
|
|
1
|
-
require 'pathname'
|
2
|
-
|
3
1
|
module Kaiseki
|
4
|
-
VERSION = '
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
'
|
11
|
-
'
|
12
|
-
|
13
|
-
|
14
|
-
'
|
15
|
-
'
|
16
|
-
'
|
17
|
-
|
18
|
-
'
|
19
|
-
'
|
20
|
-
'
|
21
|
-
|
22
|
-
|
23
|
-
'
|
24
|
-
'
|
25
|
-
|
26
|
-
'
|
27
|
-
'
|
28
|
-
|
29
|
-
'
|
30
|
-
'
|
31
|
-
|
32
|
-
'
|
33
|
-
|
34
|
-
'
|
35
|
-
|
36
|
-
|
37
|
-
'
|
38
|
-
'
|
39
|
-
'
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
'
|
44
|
-
'
|
45
|
-
'
|
46
|
-
'
|
47
|
-
|
48
|
-
|
49
|
-
|
2
|
+
VERSION = '1.0.1'
|
3
|
+
file_path = File.dirname __FILE__
|
4
|
+
|
5
|
+
#load basic kaiseki classes
|
6
|
+
require file_path + '/stream'
|
7
|
+
require file_path + '/parseable'
|
8
|
+
require file_path + '/parse_error'
|
9
|
+
require file_path + '/parse_result'
|
10
|
+
|
11
|
+
#load standard class modifiers
|
12
|
+
require file_path + '/mod_object'
|
13
|
+
require file_path + '/mod_string'
|
14
|
+
require file_path + '/mod_regexp'
|
15
|
+
require file_path + '/mod_symbol'
|
16
|
+
require file_path + '/mod_proc'
|
17
|
+
require file_path + '/mod_file'
|
18
|
+
require file_path + '/mod_kernel'
|
19
|
+
|
20
|
+
#load parsers
|
21
|
+
require file_path + '/parser_basic'
|
22
|
+
require file_path + '/parser_string'
|
23
|
+
require file_path + '/parser_regexp'
|
24
|
+
require file_path + '/parser_symbol'
|
25
|
+
require file_path + '/parser_eof'
|
26
|
+
|
27
|
+
require file_path + '/parser_multi'
|
28
|
+
require file_path + '/parser_sequence'
|
29
|
+
require file_path + '/parser_choice'
|
30
|
+
require file_path + '/parser_repeat'
|
31
|
+
|
32
|
+
require file_path + '/parser_package'
|
33
|
+
|
34
|
+
#load predicates
|
35
|
+
require file_path + '/predicate_and'
|
36
|
+
require file_path + '/predicate_not'
|
37
|
+
require file_path + '/predicate_skip'
|
38
|
+
|
39
|
+
#load result modifiers
|
40
|
+
require file_path + '/result_override'
|
41
|
+
require file_path + '/result_merge'
|
42
|
+
require file_path + '/result_cast'
|
43
|
+
require file_path + '/result_filter'
|
44
|
+
require file_path + '/node'
|
45
|
+
|
46
|
+
#load grammar classes
|
47
|
+
require file_path + '/grammar'
|
48
|
+
require file_path + '/rule'
|
49
|
+
require file_path + '/action'
|
50
|
+
|
51
|
+
#load varible manipulators
|
52
|
+
require file_path + '/var_set'
|
53
|
+
require file_path + '/var_get'
|
54
|
+
require file_path + '/var_insert'
|
55
|
+
end
|
data/lib/mod_file.rb
ADDED
data/lib/mod_kernel.rb
ADDED
data/lib/mod_object.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
class Object
|
2
|
+
def must_be item
|
3
|
+
raise TypeError, "can't convert #{self.class} into #{item}" unless self.is_a? item
|
4
|
+
true
|
5
|
+
end
|
6
|
+
|
7
|
+
def must_have property, value
|
8
|
+
raise StandardError, "##{property} must be #{value} (#{self.send(property)})" unless self.send(property) == value
|
9
|
+
true
|
10
|
+
end
|
11
|
+
end
|
data/lib/mod_proc.rb
ADDED
data/lib/mod_regexp.rb
ADDED
data/lib/mod_string.rb
ADDED
data/lib/mod_symbol.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
class Symbol
|
2
|
+
include Kaiseki::Parseable
|
3
|
+
|
4
|
+
def to_parseable
|
5
|
+
if self == :EOF
|
6
|
+
Kaiseki::EOFParser.new
|
7
|
+
else
|
8
|
+
Kaiseki::SymbolParser.new self
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_instance_variable
|
13
|
+
if self[0] == '@'
|
14
|
+
self
|
15
|
+
else
|
16
|
+
:"@#{self}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def from_instance_variable
|
21
|
+
if self[0] == '@'
|
22
|
+
self[1..-1].to_sym
|
23
|
+
else
|
24
|
+
self
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/node.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class Node
|
3
|
+
def initialize args = [], global = nil
|
4
|
+
args.must_be Array
|
5
|
+
if global
|
6
|
+
global.each_pair do |key, value|
|
7
|
+
instance_variable_set key.to_instance_variable, value
|
8
|
+
end
|
9
|
+
end
|
10
|
+
list = args.reverse
|
11
|
+
self.class.arg_names.each do |name|
|
12
|
+
value = []
|
13
|
+
while 0 >= self.class.arity[name] or value.length < self.class.arity[name]
|
14
|
+
if !list.empty?
|
15
|
+
value << list.pop
|
16
|
+
elsif value.empty? and self.class.defaults.key?(name)
|
17
|
+
value << self.class.defaults[name]
|
18
|
+
break
|
19
|
+
else
|
20
|
+
if self.class.arity[name] <= 0
|
21
|
+
break
|
22
|
+
else
|
23
|
+
raise ArgumentError, "wrong number of arguments (#{value.length} for #{self.class.arity[name]})"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
if self.class.arity[name] == 1
|
28
|
+
value = value[0]
|
29
|
+
elsif self.class.arity[name] == 0
|
30
|
+
if value.length < 1
|
31
|
+
value = nil
|
32
|
+
elsif value.length == 1
|
33
|
+
value = value[0]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
instance_variable_set name.to_instance_variable, value
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def eval global = nil, &block
|
41
|
+
value = instance_eval &block
|
42
|
+
if global
|
43
|
+
(instance_variables.collect {|n| n.from_instance_variable } - self.class.arg_names).each do |n|
|
44
|
+
global[n] = instance_variable_get n.to_instance_variable
|
45
|
+
end
|
46
|
+
end
|
47
|
+
value
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class << Node
|
52
|
+
def subclass args, options = {}
|
53
|
+
args.must_be Array
|
54
|
+
Class.new(self).bind args, options
|
55
|
+
end
|
56
|
+
|
57
|
+
def bind args, options = {}
|
58
|
+
args.must_be Array
|
59
|
+
raise "can't bind parent NodeClass" if self == Node
|
60
|
+
define_singleton_method(:arg_names) { args }
|
61
|
+
define_singleton_method(:arity) { Hash.new {|hash, key| 1 }.merge(options[:arity] || {}) }
|
62
|
+
define_singleton_method(:defaults) { options[:defaults] || {} }
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
66
|
+
def arg_names
|
67
|
+
[]
|
68
|
+
end
|
69
|
+
|
70
|
+
def arity
|
71
|
+
{}
|
72
|
+
end
|
73
|
+
|
74
|
+
def defaults
|
75
|
+
{}
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/lib/parse_error.rb
ADDED
data/lib/parse_result.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class ParseResult
|
3
|
+
attr_reader :result, :error
|
4
|
+
|
5
|
+
def initialize &block
|
6
|
+
begin
|
7
|
+
catch :SkipSuccess do
|
8
|
+
@result = block.call
|
9
|
+
return
|
10
|
+
end
|
11
|
+
@result = '(skipped)'
|
12
|
+
rescue ParseError => e
|
13
|
+
@error = e
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def has_errors?
|
18
|
+
!!@error
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/parseable.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
module Parseable
|
3
|
+
def to_parseable
|
4
|
+
self
|
5
|
+
end
|
6
|
+
|
7
|
+
def parse stream, options = {}
|
8
|
+
self.to_parseable.parse! stream.to_stream, options
|
9
|
+
end
|
10
|
+
|
11
|
+
def & other
|
12
|
+
SequenceParser.new self, other
|
13
|
+
end
|
14
|
+
|
15
|
+
def | other
|
16
|
+
ChoiceParser.new self, other
|
17
|
+
end
|
18
|
+
|
19
|
+
def repeat min, max = nil
|
20
|
+
RepeatParser.new self, min, max
|
21
|
+
end
|
22
|
+
|
23
|
+
def optional
|
24
|
+
repeat 0, 1
|
25
|
+
end
|
26
|
+
|
27
|
+
def zero_or_more
|
28
|
+
repeat 0
|
29
|
+
end
|
30
|
+
|
31
|
+
def one_or_more
|
32
|
+
repeat 1
|
33
|
+
end
|
34
|
+
|
35
|
+
def and?
|
36
|
+
AndPredicate.new self
|
37
|
+
end
|
38
|
+
|
39
|
+
def not!
|
40
|
+
NotPredicate.new self
|
41
|
+
end
|
42
|
+
|
43
|
+
def skip
|
44
|
+
SkipPredicate.new self
|
45
|
+
end
|
46
|
+
|
47
|
+
def override options
|
48
|
+
OverrideResult.new self, options
|
49
|
+
end
|
50
|
+
|
51
|
+
def merge
|
52
|
+
MergeResult.new self
|
53
|
+
end
|
54
|
+
|
55
|
+
def cast to_class
|
56
|
+
CastResult.new self, to_class
|
57
|
+
end
|
58
|
+
|
59
|
+
def filter node = Node.subclass([:result], :arity => {:result => 0}), &block
|
60
|
+
FilterResult.new self, node, &block
|
61
|
+
end
|
62
|
+
|
63
|
+
def set *vars
|
64
|
+
SetVar.new self, *vars
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -1,29 +1,24 @@
|
|
1
1
|
module Kaiseki
|
2
|
-
class
|
3
|
-
include
|
4
|
-
|
2
|
+
class BasicParser
|
3
|
+
include Parseable
|
5
4
|
attr_reader :expected
|
6
5
|
|
7
6
|
def initialize expected
|
8
7
|
@expected = expected
|
9
8
|
end
|
10
9
|
|
11
|
-
def parse
|
10
|
+
def parse! stream, options = {}
|
12
11
|
raise NotImplementedError
|
13
12
|
end
|
14
13
|
|
15
|
-
def to_s
|
16
|
-
"#{@expected}"
|
17
|
-
end
|
18
|
-
|
19
|
-
def to_parseable
|
20
|
-
self
|
21
|
-
end
|
22
|
-
|
23
14
|
def eql? other
|
24
15
|
other.is_a?(self.class) and other.expected == @expected
|
25
16
|
end
|
26
17
|
|
27
18
|
alias :== :eql?
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
@expected.inspect
|
22
|
+
end
|
28
23
|
end
|
29
24
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class ChoiceParser < MultiParser
|
3
|
+
def parse! stream, options = {}
|
4
|
+
stream.must_be Stream
|
5
|
+
stream.lock do
|
6
|
+
error = true
|
7
|
+
@expected.each do |n|
|
8
|
+
begin
|
9
|
+
return n.parse stream, options
|
10
|
+
rescue ParseError
|
11
|
+
next
|
12
|
+
end
|
13
|
+
end
|
14
|
+
raise ParseError.new "no valid alternatives when parsing #{self}", options
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
alias :| :append
|
19
|
+
|
20
|
+
def delimiter
|
21
|
+
'|'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/parser_eof.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class EOFParser
|
3
|
+
include Parseable
|
4
|
+
|
5
|
+
def parse! stream, options = {}
|
6
|
+
stream.must_be Stream
|
7
|
+
stream.lock do
|
8
|
+
actual = stream.getc
|
9
|
+
if actual
|
10
|
+
raise ParseError.new "unexpected character \"#{actual}\" (expected end-of-string) when parsing #{self}", options
|
11
|
+
else
|
12
|
+
throw :SkipSuccess
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def eql? other
|
18
|
+
other.is_a? self.class
|
19
|
+
end
|
20
|
+
|
21
|
+
alias :== :eql?
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
'EOF'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/parser_multi.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class MultiParser < BasicParser
|
3
|
+
def initialize *parsers
|
4
|
+
@expected = []
|
5
|
+
parsers.each do |n|
|
6
|
+
append n
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def append parseable
|
11
|
+
@expected << parseable.to_parseable
|
12
|
+
self
|
13
|
+
end
|
14
|
+
|
15
|
+
def delimiter
|
16
|
+
'--'
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
if @expected.empty?
|
21
|
+
'(empty)'
|
22
|
+
else
|
23
|
+
@expected.join ' ' + delimiter + ' '
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Kaiseki
|
2
|
+
class RegexpParser < BasicParser
|
3
|
+
def parse! stream, options = {}
|
4
|
+
stream.must_be Stream
|
5
|
+
stream.lock do
|
6
|
+
match = stream.match @expected
|
7
|
+
if match
|
8
|
+
if options[:simplify]
|
9
|
+
match.to_s
|
10
|
+
else
|
11
|
+
match
|
12
|
+
end
|
13
|
+
else
|
14
|
+
raise ParseError.new "non-matching characters when parsing #{self}", options
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|