grammar 0.5 → 0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/benchmark/json.benchmark.rb +355 -0
- data/benchmark/json.grammar.rb +56 -0
- data/benchmark/json.grammar0_5.rb +57 -0
- data/benchmark/json.ll1.rb +155 -0
- data/benchmark/json.peggy.rb +174 -0
- data/benchmark/json.re.rb +81 -0
- data/lib/grammar.rb +212 -639
- data/lib/grammar/ruby.rb +606 -0
- data/lib/grammar/ruby/code.rb +1030 -0
- data/lib/grammar/ruby0.rb +521 -0
- data/lib/grammar/ruby2cext.rb +19 -0
- data/lib/grammar/rubycall.rb +21 -0
- data/test/advanced.rb +105 -0
- data/test/atoms.rb +77 -0
- data/test/basic.rb +32 -0
- data/test/composite.rb +147 -0
- data/test/molecules.rb +125 -0
- data/test/test_demo.rb +200 -0
- data/test/test_ruby.rb +30 -0
- data/test/test_ruby0.rb +30 -0
- data/test/test_ruby2cext.rb +30 -0
- data/test/test_rubycall.rb +30 -0
- metadata +45 -28
- data/samples/fact.tcl +0 -12
- data/samples/infix2postfix.rb +0 -114
- data/samples/tcl.rb +0 -163
- data/samples/test.infix +0 -4
- data/test/test_grammar.rb +0 -274
data/samples/tcl.rb
DELETED
@@ -1,163 +0,0 @@
|
|
1
|
-
#!/bin/env ruby
|
2
|
-
|
3
|
-
require 'rubygems'
|
4
|
-
require 'cursor/io'
|
5
|
-
require 'cursor/indexed'
|
6
|
-
require 'grammar'
|
7
|
-
require 'duck'
|
8
|
-
require 'set'
|
9
|
-
|
10
|
-
class Tcl
|
11
|
-
|
12
|
-
def initialize
|
13
|
-
|
14
|
-
@variables = {}
|
15
|
-
@procs = {}
|
16
|
-
|
17
|
-
space = Grammar::Element[Set[?\ ,?\t].duck!(:==,:include?)].discard
|
18
|
-
newline = Grammar::Element[?\n]
|
19
|
-
command_separator = newline|Grammar::Element[?;]
|
20
|
-
hex = Grammar::Element[(
|
21
|
-
Set[]+(?0..?9)+(?a..?f)+(?A..?F)
|
22
|
-
).duck!(:==,:include?)]
|
23
|
-
octal = Grammar::Element[(?0..?7).duck!(:==,:===)]
|
24
|
-
alphanum = Grammar::Element[(
|
25
|
-
Set[?_]+(?0..?9)+(?a..?z)+(?A..?Z)
|
26
|
-
).duck!(:==,:include?)]
|
27
|
-
|
28
|
-
backslashed = Grammar::Element[?\\].discard+(
|
29
|
-
Grammar::Element[?a].filter { "\a" } |
|
30
|
-
Grammar::Element[?b].filter { "\b" } |
|
31
|
-
Grammar::Element[?f].filter { "\f" } |
|
32
|
-
Grammar::Element[?n].filter { "\n" } |
|
33
|
-
Grammar::Element[?r].filter { "\r" } |
|
34
|
-
Grammar::Element[?t].filter { "\t" } |
|
35
|
-
Grammar::Element[?v].filter { "\v" } |
|
36
|
-
Grammar::Element[?x].discard+hex.list1.filter { |n|
|
37
|
-
eval(%Q("\\x#{n}"))
|
38
|
-
} |
|
39
|
-
Grammar::Element[?u].discard+hex.list1 { |n| # don't know what to do with unicode
|
40
|
-
eval(%Q("\\x#{n}"))
|
41
|
-
} |
|
42
|
-
octal.list1.filter { |n|
|
43
|
-
eval(%Q("\\#{n}"))
|
44
|
-
} |
|
45
|
-
(newline.discard+space.list0).filter { " " } |
|
46
|
-
Grammar::ANY
|
47
|
-
)
|
48
|
-
|
49
|
-
braced_element = Grammar.new { |braced_element|
|
50
|
-
Grammar::Element[?\{]+braced_element.list0(Grammar::Element[?\}]) |
|
51
|
-
Grammar::Element[?\\].discard+(
|
52
|
-
(newline.discard+space.list0).filter { " " } |
|
53
|
-
Grammar::NULL.filter { "\\" }
|
54
|
-
) |
|
55
|
-
newline |
|
56
|
-
Grammar::ANY
|
57
|
-
}
|
58
|
-
braced = Grammar::Element[?\{].discard+braced_element.list0(Grammar::Element[?\}].discard)
|
59
|
-
|
60
|
-
element = Grammar.new
|
61
|
-
|
62
|
-
varname = (
|
63
|
-
alphanum |
|
64
|
-
Grammar::Element[?\:]*(2..+1.0/0)
|
65
|
-
).list1
|
66
|
-
index = Grammar::Element[?\(]+element.list1(Grammar::Element[?\)])
|
67
|
-
variable = (Grammar::Element[?\$].discard + (
|
68
|
-
varname.group(String) + index.group(String).optional |
|
69
|
-
braced.group(String)
|
70
|
-
)).filter { |var| @variables[var.to_s.to_sym].to_s }
|
71
|
-
|
72
|
-
quoted = Grammar::Element[?\"].discard+element.list1(Grammar::Element[?\"].discard)
|
73
|
-
comment = (Grammar::Element[?\#]+Grammar::ANY.list0(newline)).discard
|
74
|
-
|
75
|
-
commander = lambda { |terminator|
|
76
|
-
word_terminator = space.list1|+command_separator|+terminator
|
77
|
-
word = ((braced|quoted)+word_terminator|element.list1(word_terminator)).
|
78
|
-
group(String).filter {|x,t| t.concat(x)}
|
79
|
-
command = space.list0 + (
|
80
|
-
comment |
|
81
|
-
word.list0(command_separator.discard|+terminator).
|
82
|
-
filter(Array) { |com,ret|
|
83
|
-
com.empty? ? ret : ret.replace(send(*com).to_s)
|
84
|
-
}
|
85
|
-
)
|
86
|
-
command.list0(terminator.discard)
|
87
|
-
}
|
88
|
-
|
89
|
-
bracketed = Grammar::Element[?[].discard+commander[Grammar::Element[?]]]
|
90
|
-
|
91
|
-
@interpreter = commander[Grammar::EOF]
|
92
|
-
|
93
|
-
element << (backslashed | bracketed | variable | newline | Grammar::ANY)
|
94
|
-
|
95
|
-
end
|
96
|
-
|
97
|
-
def interpret(cursor)
|
98
|
-
@interpreter.scan(cursor,"",false)
|
99
|
-
end
|
100
|
-
|
101
|
-
def method_missing(name,*args)
|
102
|
-
vars,body = *@procs[name]
|
103
|
-
return "<#{name}#{args.inspect}>" if !body
|
104
|
-
variables = @variables
|
105
|
-
@variables = {}
|
106
|
-
vars.zip(args).each { |var,val| @variables[var.to_sym] = val }
|
107
|
-
ret = interpret(body.to_cursor)
|
108
|
-
@variables = variables
|
109
|
-
ret
|
110
|
-
end
|
111
|
-
|
112
|
-
def proc(name,args,body)
|
113
|
-
@procs[name.to_sym] = [args,body]
|
114
|
-
""
|
115
|
-
end
|
116
|
-
|
117
|
-
def set(name,value)
|
118
|
-
@variables[name.to_sym] = value
|
119
|
-
end
|
120
|
-
|
121
|
-
def if(condition,body)
|
122
|
-
# should really use expr to get condition
|
123
|
-
unless %w(0 false no off).include?(condition.to_s)
|
124
|
-
interpret(body.to_cursor)
|
125
|
-
end
|
126
|
-
# need to handle elsif and else
|
127
|
-
""
|
128
|
-
end
|
129
|
-
|
130
|
-
def sum(*values)
|
131
|
-
values.inject(0) { |sum, v| sum + eval(v) }
|
132
|
-
end
|
133
|
-
|
134
|
-
def product(*values)
|
135
|
-
values.inject(1) { |sum, v| sum * eval(v) }
|
136
|
-
end
|
137
|
-
|
138
|
-
def subtract(a,b)
|
139
|
-
eval(a)-eval(b)
|
140
|
-
end
|
141
|
-
|
142
|
-
def divide(a,b)
|
143
|
-
eval(a)/eval(b)
|
144
|
-
end
|
145
|
-
|
146
|
-
def puts(str)
|
147
|
-
$stdout.print(str,"\n")
|
148
|
-
""
|
149
|
-
end
|
150
|
-
|
151
|
-
def concat(*args)
|
152
|
-
args.inject("") { |concatenated, arg| concatenated.concat(arg) }
|
153
|
-
end
|
154
|
-
|
155
|
-
end
|
156
|
-
|
157
|
-
if $0==__FILE__
|
158
|
-
result = Tcl.new.interpret($stdin.to_cursor)
|
159
|
-
p result
|
160
|
-
result
|
161
|
-
end
|
162
|
-
|
163
|
-
|
data/samples/test.infix
DELETED
data/test/test_grammar.rb
DELETED
@@ -1,274 +0,0 @@
|
|
1
|
-
#!/bin/env ruby
|
2
|
-
|
3
|
-
require 'rubygems'
|
4
|
-
require 'test/unit'
|
5
|
-
require 'test/unit/collector'
|
6
|
-
require 'cursor/indexed'
|
7
|
-
require 'grammar'
|
8
|
-
|
9
|
-
module Test
|
10
|
-
module Unit
|
11
|
-
class AutoRunner
|
12
|
-
alias_method(:_options_,:options)
|
13
|
-
def options
|
14
|
-
@options = _options_
|
15
|
-
@options.on('-i', '--iterations=NUMBER', Float,
|
16
|
-
"Randomly run tests for a number of iterations.") do |iterations|
|
17
|
-
$random_iterations = iterations
|
18
|
-
end
|
19
|
-
@options.on('-s', '--seed=NUMBER', Integer,
|
20
|
-
"Random seed.") do |seed|
|
21
|
-
$random_seed = seed.nonzero?
|
22
|
-
end
|
23
|
-
@options
|
24
|
-
end
|
25
|
-
alias_method(:_run_,:run)
|
26
|
-
def run
|
27
|
-
$output_level = @output_level
|
28
|
-
$random_seed ||= (srand;srand)
|
29
|
-
srand($random_seed)
|
30
|
-
_run_
|
31
|
-
end
|
32
|
-
end
|
33
|
-
module Collector
|
34
|
-
alias_method(:_add_suite_,:add_suite)
|
35
|
-
def add_suite(destination, suite)
|
36
|
-
_add_suite_(destination, suite)
|
37
|
-
if $random_iterations
|
38
|
-
(class << suite.tests;self;end).class_eval {
|
39
|
-
def each
|
40
|
-
n = size
|
41
|
-
($random_iterations*n).to_i.times {
|
42
|
-
yield(slice(rand(n)))
|
43
|
-
}
|
44
|
-
end
|
45
|
-
}
|
46
|
-
end
|
47
|
-
destination
|
48
|
-
end
|
49
|
-
end
|
50
|
-
class TestSuite
|
51
|
-
def run(result, &progress_block)
|
52
|
-
yield(STARTED, name)
|
53
|
-
catch(:stop_suite) {
|
54
|
-
@tests.each { |test|
|
55
|
-
catch(:invalid_test) {
|
56
|
-
test.run(result, &progress_block)
|
57
|
-
}
|
58
|
-
}
|
59
|
-
}
|
60
|
-
yield(FINISHED, name)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
class RandomTestCase < TestCase
|
64
|
-
def self.suite
|
65
|
-
suite = super
|
66
|
-
puts("random_seed: #{$random_seed}") if !suite.tests.empty? and $output_level>=UI::NORMAL
|
67
|
-
suite
|
68
|
-
end
|
69
|
-
undef_method(:default_test) # so that RandomTestCase is empty
|
70
|
-
def teardown
|
71
|
-
if not passed?
|
72
|
-
puts("\nrandom_seed: #{$random_seed}")
|
73
|
-
throw(:stop_suite)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
|
81
|
-
class Grammar
|
82
|
-
|
83
|
-
class Test < ::Test::Unit::RandomTestCase
|
84
|
-
|
85
|
-
class Grammars
|
86
|
-
include ::Test::Unit::Assertions
|
87
|
-
def initialize
|
88
|
-
@grammar = []
|
89
|
-
@match = []
|
90
|
-
@parsed = []
|
91
|
-
@mismatch = []
|
92
|
-
@partial_match = []
|
93
|
-
end
|
94
|
-
def get
|
95
|
-
i = rand(@grammar.size.nonzero? || throw(:invalid_test))
|
96
|
-
return @grammar[i],@match[i],@parsed[i],@mismatch[i],@partial_match[i]
|
97
|
-
end
|
98
|
-
def add(grammar,match,parsed,mismatch=nil,partial_match=nil)
|
99
|
-
puts("#{grammar.inspect} #{match.inspect} #{parsed.inspect} #{mismatch.inspect} #{partial_match.inspect}") if
|
100
|
-
$output_level>=::Test::Unit::UI::VERBOSE
|
101
|
-
match.size.times { |i|
|
102
|
-
assert_equal(parsed[i],grammar.scan(match[i].to_cursor))
|
103
|
-
}
|
104
|
-
if mismatch
|
105
|
-
assert_raise(Grammar::Error){p grammar.scan(mismatch.to_cursor)}
|
106
|
-
assert_equal(false,grammar.scan(mismatch.to_cursor,[],true))
|
107
|
-
end
|
108
|
-
if partial_match
|
109
|
-
assert_raise(Grammar::Error){grammar.scan(partial_match.to_cursor)}
|
110
|
-
end
|
111
|
-
@grammar << grammar
|
112
|
-
@match << match
|
113
|
-
@parsed << parsed
|
114
|
-
@mismatch << mismatch
|
115
|
-
@partial_match << partial_match
|
116
|
-
nil
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
def self.suite
|
121
|
-
suite = super
|
122
|
-
self.plant
|
123
|
-
suite
|
124
|
-
end
|
125
|
-
|
126
|
-
def self.plant
|
127
|
-
@@grammars = Grammars.new
|
128
|
-
end
|
129
|
-
|
130
|
-
def test_Sequence
|
131
|
-
partial = rand(2)==1
|
132
|
-
value = ["a","bc"][rand(2)]
|
133
|
-
match = value.dup
|
134
|
-
if partial
|
135
|
-
match = [match,match[0,1+rand(value.size)]]
|
136
|
-
else
|
137
|
-
match = [match]
|
138
|
-
end
|
139
|
-
parsed = match.map{|s|s.unpack("C*")}
|
140
|
-
@@grammars.add(Grammar::Sequence.new(value,partial),match,parsed,"")
|
141
|
-
end
|
142
|
-
|
143
|
-
def test_Element
|
144
|
-
value = [?a,?b][rand(2)]
|
145
|
-
match = ["" << value]
|
146
|
-
parsed = [[value]]
|
147
|
-
@@grammars.add(Grammar::Element.new(value),match,parsed,"")
|
148
|
-
end
|
149
|
-
|
150
|
-
def test_NULL
|
151
|
-
@@grammars.add(Grammar::NULL,[""],[[]])
|
152
|
-
end
|
153
|
-
|
154
|
-
def test_or
|
155
|
-
grammar1,match1,parsed1,mismatch1,partial1 = @@grammars.get
|
156
|
-
grammar2,match2,parsed2,mismatch2,partial2 = @@grammars.get
|
157
|
-
i = rand(match1.size)
|
158
|
-
match1 = match1[i]
|
159
|
-
parsed1 = parsed1[i]
|
160
|
-
i = rand(match2.size)
|
161
|
-
match2 = match2[i]
|
162
|
-
parsed2 = parsed2[i]
|
163
|
-
begin
|
164
|
-
# match2 shouldn't match grammar1
|
165
|
-
grammar1.scan(match2.to_cursor,[],true) and throw(:invalid_test)
|
166
|
-
rescue Grammar::Error
|
167
|
-
throw(:invalid_test) # partial match
|
168
|
-
end
|
169
|
-
@@grammars.add(
|
170
|
-
grammar1|grammar2,
|
171
|
-
[match1,match2],
|
172
|
-
[parsed1,parsed2],
|
173
|
-
mismatch1==mismatch2 ? mismatch1 : nil,
|
174
|
-
partial1==partial2 ? partial1 : nil
|
175
|
-
)
|
176
|
-
end
|
177
|
-
|
178
|
-
def test_plus
|
179
|
-
grammar1,match1,parsed1,mismatch1,partial1 = @@grammars.get
|
180
|
-
grammar2,match2,parsed2,mismatch2,partial2 = @@grammars.get
|
181
|
-
i = rand(match1.size)
|
182
|
-
match1 = match1[i]
|
183
|
-
parsed1 = parsed1[i]
|
184
|
-
i = rand(match2.size)
|
185
|
-
match2 = match2[i]
|
186
|
-
parsed2 = parsed2[i]
|
187
|
-
# grammar1 shouldn't eat into match2
|
188
|
-
begin
|
189
|
-
grammar1.scan((match1+match2).to_cursor)==parsed1 or
|
190
|
-
throw(:invalid_test)
|
191
|
-
rescue Grammar::Error
|
192
|
-
throw(:invalid_test)
|
193
|
-
end
|
194
|
-
@@grammars.add(
|
195
|
-
grammar1+grammar2,
|
196
|
-
[match1+match2],
|
197
|
-
[parsed1+parsed2],
|
198
|
-
mismatch1,
|
199
|
-
partial1 || (mismatch2 && match1+mismatch2)
|
200
|
-
)
|
201
|
-
end
|
202
|
-
|
203
|
-
def test_Grammar
|
204
|
-
grammar1,match1,parsed1,mismatch1,partial1 = @@grammars.get
|
205
|
-
grammar2,match2,parsed2,mismatch2,partial2 = @@grammars.get
|
206
|
-
i = rand(match1.size)
|
207
|
-
match1 = match1[i]
|
208
|
-
parsed1 = parsed1[i]
|
209
|
-
i = rand(match2.size)
|
210
|
-
match2 = match2[i]
|
211
|
-
parsed2 = parsed2[i]
|
212
|
-
!match1.empty? or throw(:invalid_test)
|
213
|
-
begin
|
214
|
-
(grammar1.scan((match1+match1).to_cursor)==parsed1 and
|
215
|
-
grammar1.scan((match1+match2).to_cursor)==parsed1 and
|
216
|
-
grammar2.scan((match2+match2).to_cursor)==parsed2) or
|
217
|
-
throw(:invalid_test)
|
218
|
-
grammar1.scan(match2.to_cursor,[],true) and throw(:invalid_test)
|
219
|
-
rescue Grammar::Error
|
220
|
-
throw(:invalid_test)
|
221
|
-
end
|
222
|
-
grammar = Grammar.new
|
223
|
-
grammar << grammar1+(grammar|Grammar::NULL)+grammar2
|
224
|
-
@@grammars.add(
|
225
|
-
grammar,
|
226
|
-
[match1+match2,match1+match1+match1+match2+match2+match2],
|
227
|
-
[parsed1+parsed2,parsed1+parsed1+parsed1+parsed2+parsed2+parsed2],
|
228
|
-
mismatch1,
|
229
|
-
partial1
|
230
|
-
)
|
231
|
-
end
|
232
|
-
|
233
|
-
def test_times
|
234
|
-
grammar1,match1,parsed1,mismatch1,partial1 = @@grammars.get
|
235
|
-
begin
|
236
|
-
grammar1.scan("".to_cursor,[],true) and throw(:invalid_test)
|
237
|
-
rescue Grammar::Error
|
238
|
-
throw(:invalid_test)
|
239
|
-
end
|
240
|
-
min = rand(2)
|
241
|
-
diff = rand(4)
|
242
|
-
match = ""
|
243
|
-
parsed = []
|
244
|
-
match0 = nil
|
245
|
-
parsed0 = nil
|
246
|
-
(min+rand(diff+1)).times {
|
247
|
-
i = rand(match1.size)
|
248
|
-
match.concat(match1[i])
|
249
|
-
parsed.concat(parsed1[i])
|
250
|
-
if match0
|
251
|
-
begin
|
252
|
-
grammar1.scan((match0+match1[i]).to_cursor)==parsed0 or
|
253
|
-
throw(:invalid_test)
|
254
|
-
rescue Grammar::Error
|
255
|
-
throw(:invalid_test)
|
256
|
-
end
|
257
|
-
end
|
258
|
-
match0 = match1[i]
|
259
|
-
parsed0 = parsed1[i]
|
260
|
-
}
|
261
|
-
diff = 1.0/0.0 if diff==3
|
262
|
-
multiplier = (diff.zero? && rand(2).zero?) ? min : (min..(min+diff))
|
263
|
-
@@grammars.add(
|
264
|
-
grammar1*multiplier,
|
265
|
-
[match],
|
266
|
-
[parsed],
|
267
|
-
min.zero? ? nil : mismatch1,
|
268
|
-
min.zero? ? nil : (partial1 || (min>1 && match1[rand(match1.size)]))
|
269
|
-
)
|
270
|
-
end
|
271
|
-
|
272
|
-
end
|
273
|
-
end
|
274
|
-
|