rparsec 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/rparsec.rb CHANGED
@@ -1,3 +1,3 @@
1
- %w{
2
- parsers operators keywords expressions
1
+ %w{
2
+ parsers operators keywords expressions
3
3
  }.each {|lib| require "rparsec/#{lib}"}
@@ -1,66 +1,81 @@
1
-
2
-
3
- class ParseContext
4
- attr_reader :error, :src, :index, :result
5
- attr_writer :error, :index, :result
6
- def initialize(src, index=0, error=nil)
7
- @src, @index, @error = src, index, error
8
- end
9
-
10
- def scanner
11
- @scanner = StringScanner.new(src) if @scanner.nil?
12
- @scanner.pos= @index
13
- @scanner
14
- end
15
- def prepare_error
16
- @error.flatten! if @error.kind_of?(Array)
17
- end
18
- def to_msg
19
- return '' if @error.nil?
20
- return @error.msg unless @error.kind_of?(Array)
21
- @error.map{|e|e.msg}.join(' or ')
22
- end
23
- def error_input
24
- return nil if @error.nil?
25
- err = @error
26
- err = err.last if err.kind_of? Array
27
- err.input
28
- end
29
- def reset_error
30
- @error = nil
31
- end
32
- def current
33
- @src[@index]
34
- end
35
- def eof
36
- @index >= @src.length
37
- end
38
- def available
39
- @src.length - @index
40
- end
41
- def peek i
42
- @src[@index+i]
43
- end
44
- def next
45
- @index += 1
46
- end
47
- def advance n
48
- @index += n
49
- end
50
- def retn(val)
51
- @result = val
52
- true
53
- end
54
- def failure(msg=nil)
55
- @error = Failure.new(@index, get_current_input, msg)
56
- return false
57
- end
58
- def expecting(expected=nil)
59
- @error = Expected.new(@index, get_current_input, expected)
60
- return false
61
- end
62
- def get_current_input
63
- return nil if eof
64
- current
65
- end
66
- end
1
+
2
+
3
+ class ParseContext
4
+ attr_reader :error, :src, :index, :result
5
+ attr_writer :error, :index, :result
6
+
7
+ def initialize(src, index=0, error=nil)
8
+ @src, @index, @error = src, index, error
9
+ end
10
+
11
+ def scanner
12
+ @scanner = StringScanner.new(src) if @scanner.nil?
13
+ @scanner.pos= @index
14
+ @scanner
15
+ end
16
+
17
+ def prepare_error
18
+ @error.flatten! if @error.kind_of?(Array)
19
+ end
20
+
21
+ def to_msg
22
+ return '' if @error.nil?
23
+ return @error.msg unless @error.kind_of?(Array)
24
+ @error.map{|e|e.msg}.join(' or ')
25
+ end
26
+
27
+ def error_input
28
+ return nil if @error.nil?
29
+ err = @error
30
+ err = err.last if err.kind_of? Array
31
+ err.input
32
+ end
33
+
34
+ def reset_error
35
+ @error = nil
36
+ end
37
+
38
+ def current
39
+ @src[@index]
40
+ end
41
+
42
+ def eof
43
+ @index >= @src.length
44
+ end
45
+
46
+ def available
47
+ @src.length - @index
48
+ end
49
+
50
+ def peek i
51
+ @src[@index+i]
52
+ end
53
+
54
+ def next
55
+ @index += 1
56
+ end
57
+
58
+ def advance n
59
+ @index += n
60
+ end
61
+
62
+ def retn(val)
63
+ @result = val
64
+ true
65
+ end
66
+
67
+ def failure(msg=nil)
68
+ @error = Failure.new(@index, get_current_input, msg)
69
+ return false
70
+ end
71
+
72
+ def expecting(expected=nil)
73
+ @error = Expected.new(@index, get_current_input, expected)
74
+ return false
75
+ end
76
+
77
+ def get_current_input
78
+ return nil if eof
79
+ current
80
+ end
81
+ end
@@ -1,20 +1,23 @@
1
- require 'rparsec/misc'
2
- class ParserException < StandardError
3
- extend DefHelper
4
- def_readable :index
5
- end
6
- class Failure
7
- def initialize(ind, input, msg=nil)
8
- @index, @input, @msg = ind, input, msg
9
- end
10
- attr_reader :index, :input
11
- attr_writer :index
12
- def msg
13
- return @msg.to_s
14
- end
15
- Precedence = 100
16
- end
17
-
18
- class Expected < Failure
19
- Precedence = 100
1
+ require 'rparsec/misc'
2
+ class ParserException < StandardError
3
+ extend DefHelper
4
+ def_readable :index
5
+ end
6
+ class Failure
7
+ def initialize(ind, input, message=nil)
8
+ @index, @input, @msg = ind, input, message
9
+ end
10
+
11
+ attr_reader :index, :input
12
+ attr_writer :index
13
+
14
+ def msg
15
+ return @msg.to_s
16
+ end
17
+
18
+ Precedence = 100
19
+ end
20
+
21
+ class Expected < Failure
22
+ Precedence = 100
20
23
  end
@@ -1,137 +1,180 @@
1
- require 'rparsec/parser'
2
-
3
- Associativities = [:prefix, :postfix, :infixn, :infixr, :infixl]
4
- #
5
- # This class holds information about operator precedences
6
- # and associativities.
7
- # prefix, postfix, infixl, infixr, infixn can be called
8
- # to register operators.
9
- #
10
- class OperatorTable
11
- #
12
- # operators attribute is used internally. Do not access it.
13
- #
14
- attr_reader :operators
15
- #
16
- # Re-initialize the operator table.
17
- #
18
- def reinit
19
- @operators = []
20
- end
21
- #
22
- # To create an OperatorTable instance.
23
- # If a block is given, it is invoked to do post-instantiation.
24
- # For example:
25
- #
26
- # OperatorTable.new do |tbl|
27
- # tbl.infixl(char(?+) >> Plus)
28
- # tbl.infixl(char(?-) >> Minus)
29
- # tbl.prefix(char(?-) >> Neg)
30
- # end
31
- #
32
- def self.new
33
- this = allocate
34
- this.reinit
35
- if block_given?
36
- yield this
37
- end
38
- this
39
- end
40
- private
41
- #
42
- # To define methods for registering operator.
43
- # This is typically used internally.
44
- #
45
- def self.def_operator(*kinds)
46
- kinds.each do |kind|
47
- define_method(kind) do |op, precedence|
48
- add(kind, op, precedence)
49
- end
50
- end
51
- end
52
- def_operator(*Associativities)
53
- def add(*entry)
54
- @operators << entry
55
- self
56
- end
57
- end
58
-
59
- #
60
- # This module helps build an expression parser
61
- # using an OperatorTable instance and a parser
62
- # that parses the term expression.
63
- #
64
- module Expressions
65
- private
66
- def self.array_to_dict arr
67
- result = {}
68
- arr.each_with_index do |key,i|
69
- result [key] = i unless result.include? key
70
- end
71
- result
72
- end
73
- KindPrecedence = array_to_dict Associativities
74
- public
75
- #
76
- # build an expression parser using the given term parser
77
- # and operator table.
78
- # When _delim_ is specified, patterns recognized by _delim_
79
- # is automatically ignored.
80
- #
81
- def self.build(term, table, delim=nil)
82
- # sort so that higher precedence first.
83
- apply_operators(term, prepare_suites(table).sort, delim)
84
- end
85
- private
86
- def self.apply_operators(term, entries, delim)
87
- # apply operators stored in [[precedence,associativity],[op...]] starting from beginning.
88
- entries.inject(term) do |result, entry|
89
- key, ops = *entry
90
- null, kind_index = *key
91
- op = ops[0]
92
- op = Parsers.sum(*ops) if ops.length>1
93
- apply_operator(result, op, Associativities[kind_index], delim)
94
- end
95
- end
96
- def self.apply_operator(term, op, kind, delim)
97
- term, op = ignore_rest(term, delim), ignore_rest(op, delim)
98
- # we could use send here,
99
- # but explicit case stmt is more straight forward and less coupled with names.
100
- # performance might be another benefit,
101
- # though it is not clear whether meta-code is indeed slower than regular ones at all.
102
- case kind
103
- when :prefix
104
- term.prefix(op)
105
- when :postfix
106
- term.postfix(op)
107
- when :infixl
108
- term.infixl(op)
109
- when :infixr
110
- term.infixr(op)
111
- when :infixn
112
- term.infixn(op)
113
- else
114
- raise ArgumentError, "unknown associativity: #{kind}"
115
- end
116
- end
117
- def self.ignore_rest(parser, delim)
118
- return parser if delim.nil?
119
- parser << delim
120
- end
121
- def self.prepare_suites(table)
122
- # create a hash with [precedence, associativity] as key, and op as value.
123
- suites = {}
124
- table.operators.each do |entry|
125
- kind, op, precedence = *entry
126
- key = [-precedence, KindPrecedence[kind]]
127
- suite = suites[key]
128
- if suite.nil?
129
- suite = [op]
130
- suites[key] = suite
131
- else
132
- suite << op
133
- end
134
- end
135
- suites
136
- end
1
+ require 'rparsec/parser'
2
+
3
+ Associativities = [:prefix, :postfix, :infixn, :infixr, :infixl]
4
+ #
5
+ # This class holds information about operator precedences
6
+ # and associativities.
7
+ # prefix, postfix, infixl, infixr, infixn can be called
8
+ # to register operators.
9
+ #
10
+ class OperatorTable
11
+ #
12
+ # operators attribute is used internally. Do not access it.
13
+ #
14
+ attr_reader :operators
15
+
16
+ #
17
+ # Re-initialize the operator table. Internal use only.
18
+ #
19
+ def reinit
20
+ @operators = []
21
+ end
22
+
23
+ #
24
+ # To create an OperatorTable instance.
25
+ # If a block is given, it is invoked to do post-instantiation.
26
+ # For example:
27
+ #
28
+ # OperatorTable.new do |tbl|
29
+ # tbl.infixl(char(?+) >> Plus, 10)
30
+ # tbl.infixl(char(?-) >> Minus, 10)
31
+ # tbl.infixl(char(?*) >> Mul, 20)
32
+ # tbl.infixl(char(?/) >> Div, 20)
33
+ # tbl.prefix(char(?-) >> Neg, 50)
34
+ # end
35
+ #
36
+ def self.new
37
+ this = allocate
38
+ this.reinit
39
+ if block_given?
40
+ yield this
41
+ end
42
+ this
43
+ end
44
+
45
+ #
46
+ # Defines a prefix operator that returns a unary Proc object with a precedence associated.
47
+ # Returns self.
48
+ #
49
+ def prefix(op, precedence)
50
+ add(:prefix, op, precedence)
51
+ end
52
+
53
+ #
54
+ # Defines a postfix operator that returns a unary Proc object with a precedence associated.
55
+ # Returns self.
56
+ #
57
+ def postfix(op, precedence)
58
+ add(:postfix, op, precedence)
59
+ end
60
+
61
+ #
62
+ # Defines a left associative infix operator that returns a binary Proc object with a precedence
63
+ # associated. Returns self.
64
+ #
65
+ def infixl(op, precedence)
66
+ add(:infixl, op, precedence)
67
+ end
68
+
69
+ #
70
+ # Defines a right associative infix operator that returns a binary Proc object with a precedence
71
+ # associated. Returns self.
72
+ #
73
+ def infixr(op, precedence)
74
+ add(:infixr, op, precedence)
75
+ end
76
+
77
+ #
78
+ # Defines a non-associative infix operator that returns a binary Proc object with a precedence
79
+ # associated. Returns self.
80
+ #
81
+ def infixn(op, precedence)
82
+ add(:infixn, op, precedence)
83
+ end
84
+
85
+ private
86
+
87
+ def add(*entry)
88
+ @operators << entry
89
+ self
90
+ end
91
+ end
92
+
93
+ #
94
+ # This module helps build an expression parser
95
+ # using an OperatorTable instance and a parser
96
+ # that parses the term expression.
97
+ #
98
+ module Expressions
99
+ private
100
+
101
+ def self.array_to_dict arr
102
+ result = {}
103
+ arr.each_with_index do |key,i|
104
+ result [key] = i unless result.include? key
105
+ end
106
+ result
107
+ end
108
+
109
+ KindPrecedence = array_to_dict Associativities
110
+
111
+ public
112
+
113
+ #
114
+ # build an expression parser using the given term parser
115
+ # and operator table.
116
+ # When _delim_ is specified, patterns recognized by _delim_
117
+ # is automatically ignored.
118
+ #
119
+ def self.build(term, table, delim=nil)
120
+ # sort so that higher precedence first.
121
+ apply_operators(term, prepare_suites(table).sort, delim)
122
+ end
123
+
124
+ private
125
+
126
+ def self.apply_operators(term, entries, delim)
127
+ # apply operators stored in [[precedence,associativity],[op...]] starting from beginning.
128
+ entries.inject(term) do |result, entry|
129
+ key, ops = *entry
130
+ null, kind_index = *key
131
+ op = ops[0]
132
+ op = Parsers.sum(*ops) if ops.length>1
133
+ apply_operator(result, op, Associativities[kind_index], delim)
134
+ end
135
+ end
136
+
137
+ def self.apply_operator(term, op, kind, delim)
138
+ term, op = ignore_rest(term, delim), ignore_rest(op, delim)
139
+ # we could use send here,
140
+ # but explicit case stmt is more straight forward and less coupled with names.
141
+ # performance might be another benefit,
142
+ # though it is not clear whether meta-code is indeed slower than regular ones at all.
143
+ case kind
144
+ when :prefix
145
+ term.prefix(op)
146
+ when :postfix
147
+ term.postfix(op)
148
+ when :infixl
149
+ term.infixl(op)
150
+ when :infixr
151
+ term.infixr(op)
152
+ when :infixn
153
+ term.infixn(op)
154
+ else
155
+ raise ArgumentError, "unknown associativity: #{kind}"
156
+ end
157
+ end
158
+
159
+ def self.ignore_rest(parser, delim)
160
+ return parser if delim.nil?
161
+ parser << delim
162
+ end
163
+
164
+ def self.prepare_suites(table)
165
+ # create a hash with [precedence, associativity] as key, and op as value.
166
+ suites = {}
167
+ table.operators.each do |entry|
168
+ kind, op, precedence = *entry
169
+ key = [-precedence, KindPrecedence[kind]]
170
+ suite = suites[key]
171
+ if suite.nil?
172
+ suite = [op]
173
+ suites[key] = suite
174
+ else
175
+ suite << op
176
+ end
177
+ end
178
+ suites
179
+ end
137
180
  end