mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* test/ruby/sentence.rb: Sentence class implemented
based on sentgen.rb * test/ruby/sentgen.rb: removed. * test/ruby/test_assignment.rb: use sentence.rb. * test/ruby/test_yield.rb: block parameter passing emulator implemented. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13064 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
ff31ae0141
commit
9a26bd3f57
5 changed files with 482 additions and 277 deletions
12
ChangeLog
12
ChangeLog
|
@ -1,3 +1,15 @@
|
||||||
|
Thu Aug 16 19:18:26 2007 Tanaka Akira <akr@fsij.org>
|
||||||
|
|
||||||
|
* test/ruby/sentence.rb: Sentence class implemented
|
||||||
|
based on sentgen.rb
|
||||||
|
|
||||||
|
* test/ruby/sentgen.rb: removed.
|
||||||
|
|
||||||
|
* test/ruby/test_assignment.rb: use sentence.rb.
|
||||||
|
|
||||||
|
* test/ruby/test_yield.rb: block parameter passing emulator
|
||||||
|
implemented.
|
||||||
|
|
||||||
Thu Aug 16 16:48:47 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
Thu Aug 16 16:48:47 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
* configure.in (BASERUBY): check if base ruby is runnable first.
|
* configure.in (BASERUBY): check if base ruby is runnable first.
|
||||||
|
|
338
test/ruby/sentence.rb
Normal file
338
test/ruby/sentence.rb
Normal file
|
@ -0,0 +1,338 @@
|
||||||
|
# sentence
|
||||||
|
|
||||||
|
class Sentence
|
||||||
|
def initialize(ary)
|
||||||
|
@sent = ary
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
@sent.join('')
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_a
|
||||||
|
@sent
|
||||||
|
end
|
||||||
|
|
||||||
|
def [](i)
|
||||||
|
Sentence.new(@sent[i])
|
||||||
|
end
|
||||||
|
|
||||||
|
def inspect
|
||||||
|
"#<#{self.class}: #{@sent.inspect}>"
|
||||||
|
end
|
||||||
|
|
||||||
|
def subst(target, &b)
|
||||||
|
Sentence.new(subst_rec(@sent, target, &b))
|
||||||
|
end
|
||||||
|
|
||||||
|
def subst_rec(obj, target, &b)
|
||||||
|
if obj.respond_to? :to_ary
|
||||||
|
a = []
|
||||||
|
obj.each {|e| a << subst_rec(e, target, &b) }
|
||||||
|
a
|
||||||
|
elsif target === obj
|
||||||
|
yield obj
|
||||||
|
else
|
||||||
|
obj
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_subtree(&b)
|
||||||
|
if r = find_subtree_rec(@sent, &b)
|
||||||
|
Sentence.new(r)
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_subtree_rec(obj, &b)
|
||||||
|
if obj.respond_to? :to_ary
|
||||||
|
if b.call obj
|
||||||
|
return obj
|
||||||
|
else
|
||||||
|
obj.each {|e|
|
||||||
|
r = find_subtree_rec(e, &b)
|
||||||
|
return r if r
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def expand(&b)
|
||||||
|
Sentence.new(expand_rec(@sent, &b))
|
||||||
|
end
|
||||||
|
|
||||||
|
def expand_rec(obj, r=[], &b)
|
||||||
|
#puts "#{obj.inspect}\t\t#{r.inspect}"
|
||||||
|
if obj.respond_to? :to_ary
|
||||||
|
if b.call obj
|
||||||
|
obj.each {|o|
|
||||||
|
expand_rec(o, r, &b)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
a = []
|
||||||
|
obj.each {|o|
|
||||||
|
expand_rec(o, a, &b)
|
||||||
|
}
|
||||||
|
r << a
|
||||||
|
end
|
||||||
|
else
|
||||||
|
r << obj
|
||||||
|
end
|
||||||
|
r
|
||||||
|
end
|
||||||
|
|
||||||
|
def Sentence.each(syntax, sym, limit)
|
||||||
|
Gen.new(syntax).each_tree(sym, limit) {|tree|
|
||||||
|
yield Sentence.new(tree)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
class Gen
|
||||||
|
def Gen.each_tree(syntax, sym, limit, &b)
|
||||||
|
Gen.new(syntax).each_tree(sym, limit, &b)
|
||||||
|
end
|
||||||
|
|
||||||
|
def Gen.each_string(syntax, sym, limit, &b)
|
||||||
|
Gen.new(syntax).each_string(sym, limit, &b)
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(syntax)
|
||||||
|
@syntax = syntax
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.expand_syntax(syntax)
|
||||||
|
syntax = remove_underivable_rules(syntax)
|
||||||
|
syntax = expand_justempty_rules(syntax)
|
||||||
|
syntax = remove_emptyable_rules(syntax)
|
||||||
|
syntax = expand_channel_rules(syntax)
|
||||||
|
|
||||||
|
syntax = expand_noalt_rules(syntax)
|
||||||
|
syntax = reorder_rules(syntax)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.remove_underivable_rules(syntax)
|
||||||
|
deribable_syms = {}
|
||||||
|
changed = true
|
||||||
|
while changed
|
||||||
|
changed = false
|
||||||
|
syntax.each {|sym, rules|
|
||||||
|
next if deribable_syms[sym]
|
||||||
|
rules.each {|rhs|
|
||||||
|
if rhs.all? {|e| String === e || deribable_syms[e] }
|
||||||
|
deribable_syms[sym] = true
|
||||||
|
changed = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
result = {}
|
||||||
|
syntax.each {|sym, rules|
|
||||||
|
next if !deribable_syms[sym]
|
||||||
|
rules2 = []
|
||||||
|
rules.each {|rhs|
|
||||||
|
rules2 << rhs if rhs.all? {|e| String === e || deribable_syms[e] }
|
||||||
|
}
|
||||||
|
result[sym] = rules2.uniq
|
||||||
|
}
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.expand_justempty_rules(syntax)
|
||||||
|
justempty_syms = {}
|
||||||
|
changed = true
|
||||||
|
while changed
|
||||||
|
changed = false
|
||||||
|
syntax.each {|sym, rules|
|
||||||
|
next if justempty_syms[sym]
|
||||||
|
if rules.all? {|rhs| rhs.all? {|e| justempty_syms[e] } }
|
||||||
|
justempty_syms[sym] = true
|
||||||
|
changed = true
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
result = {}
|
||||||
|
syntax.each {|sym, rules|
|
||||||
|
result[sym] = rules.map {|rhs| rhs.reject {|e| justempty_syms[e] } }.uniq
|
||||||
|
}
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.expand_emptyable_syms(rhs, emptyable_syms)
|
||||||
|
if rhs.empty?
|
||||||
|
elsif rhs.length == 1
|
||||||
|
if emptyable_syms[rhs[0]]
|
||||||
|
yield rhs
|
||||||
|
yield []
|
||||||
|
else
|
||||||
|
yield rhs
|
||||||
|
end
|
||||||
|
else
|
||||||
|
butfirst = rhs[1..-1]
|
||||||
|
if emptyable_syms[rhs[0]]
|
||||||
|
expand_emptyable_syms(butfirst, emptyable_syms) {|rhs2|
|
||||||
|
yield [rhs[0]] + rhs2
|
||||||
|
yield rhs2
|
||||||
|
}
|
||||||
|
else
|
||||||
|
expand_emptyable_syms(butfirst, emptyable_syms) {|rhs2|
|
||||||
|
yield [rhs[0]] + rhs2
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.remove_emptyable_rules(syntax)
|
||||||
|
emptyable_syms = {}
|
||||||
|
changed = true
|
||||||
|
while changed
|
||||||
|
changed = false
|
||||||
|
syntax.each {|sym, rules|
|
||||||
|
next if emptyable_syms[sym]
|
||||||
|
rules.each {|rhs|
|
||||||
|
if rhs.all? {|e| emptyable_syms[e] }
|
||||||
|
emptyable_syms[sym] = true
|
||||||
|
changed = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
result = {}
|
||||||
|
syntax.each {|sym, rules|
|
||||||
|
rules2 = []
|
||||||
|
rules.each {|rhs|
|
||||||
|
expand_emptyable_syms(rhs, emptyable_syms) {|rhs2|
|
||||||
|
rules2 << rhs2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result[sym] = rules2.uniq
|
||||||
|
}
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.expand_channel_rules(syntax)
|
||||||
|
channel_rules = {}
|
||||||
|
syntax.each {|sym, rules|
|
||||||
|
channel_rules[sym] = {sym=>true}
|
||||||
|
rules.each {|rhs|
|
||||||
|
if rhs.length == 1 && Symbol === rhs[0]
|
||||||
|
channel_rules[sym][rhs[0]] = true
|
||||||
|
end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
changed = true
|
||||||
|
while changed
|
||||||
|
changed = false
|
||||||
|
channel_rules.each {|sym, set|
|
||||||
|
n1 = set.size
|
||||||
|
set.keys.each {|s|
|
||||||
|
set.update(channel_rules[s])
|
||||||
|
}
|
||||||
|
n2 = set.size
|
||||||
|
changed = true if n1 < n2
|
||||||
|
}
|
||||||
|
end
|
||||||
|
result = {}
|
||||||
|
syntax.each {|sym, rules|
|
||||||
|
rules2 = []
|
||||||
|
channel_rules[sym].each_key {|s|
|
||||||
|
syntax[s].each {|rhs|
|
||||||
|
unless rhs.length == 1 && Symbol === rhs[0]
|
||||||
|
rules2 << rhs
|
||||||
|
end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result[sym] = rules2.uniq
|
||||||
|
}
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.expand_noalt_rules(syntax)
|
||||||
|
noalt_syms = {}
|
||||||
|
syntax.each {|sym, rules|
|
||||||
|
if rules.length == 1
|
||||||
|
noalt_syms[sym] = true
|
||||||
|
end
|
||||||
|
}
|
||||||
|
result = {}
|
||||||
|
syntax.each {|sym, rules|
|
||||||
|
rules2 = []
|
||||||
|
rules.each {|rhs|
|
||||||
|
rhs2 = []
|
||||||
|
rhs.each {|e|
|
||||||
|
if noalt_syms[e]
|
||||||
|
rhs2.concat syntax[e][0]
|
||||||
|
else
|
||||||
|
rhs2 << e
|
||||||
|
end
|
||||||
|
}
|
||||||
|
rules2 << rhs2
|
||||||
|
}
|
||||||
|
result[sym] = rules2.uniq
|
||||||
|
}
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.reorder_rules(syntax)
|
||||||
|
result = {}
|
||||||
|
syntax.each {|sym, rules|
|
||||||
|
result[sym] = rules.sort_by {|rhs|
|
||||||
|
[rhs.find_all {|e| Symbol === e }.length, rhs.length]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
def each_tree(sym, limit)
|
||||||
|
generate_from_sym(sym, limit) {|_, tree|
|
||||||
|
yield tree
|
||||||
|
}
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def each_string(sym, limit)
|
||||||
|
generate_from_sym(sym, limit) {|_, tree|
|
||||||
|
yield [tree].join('')
|
||||||
|
}
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate_from_sym(sym, limit, &b)
|
||||||
|
return if limit < 0
|
||||||
|
if String === sym
|
||||||
|
yield limit, sym
|
||||||
|
else
|
||||||
|
rules = @syntax[sym]
|
||||||
|
raise "undefined rule: #{sym}" if !rules
|
||||||
|
rules.each {|rhs|
|
||||||
|
if rhs.length == 1 || rules.length == 1
|
||||||
|
limit1 = limit
|
||||||
|
else
|
||||||
|
limit1 = limit-1
|
||||||
|
end
|
||||||
|
generate_from_rhs(rhs, limit1, &b)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate_from_rhs(rhs, limit)
|
||||||
|
return if limit < 0
|
||||||
|
if rhs.empty?
|
||||||
|
yield limit, []
|
||||||
|
else
|
||||||
|
generate_from_sym(rhs[0], limit) {|limit1, child|
|
||||||
|
generate_from_rhs(rhs[1..-1], limit1) {|limit2, arr|
|
||||||
|
yield limit2, [child, *arr]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
|
@ -1,259 +0,0 @@
|
||||||
# sentence generator
|
|
||||||
|
|
||||||
class SentGen
|
|
||||||
def SentGen.each_tree(syntax, sym, limit, &b)
|
|
||||||
SentGen.new(syntax).each_tree(sym, limit, &b)
|
|
||||||
end
|
|
||||||
|
|
||||||
def SentGen.each_string(syntax, sym, limit, &b)
|
|
||||||
SentGen.new(syntax).each_string(sym, limit, &b)
|
|
||||||
end
|
|
||||||
|
|
||||||
def initialize(syntax)
|
|
||||||
@syntax = syntax
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.expand_syntax(syntax)
|
|
||||||
syntax = remove_underivable_rules(syntax)
|
|
||||||
syntax = expand_justempty_rules(syntax)
|
|
||||||
syntax = remove_emptyable_rules(syntax)
|
|
||||||
syntax = expand_channel_rules(syntax)
|
|
||||||
|
|
||||||
syntax = expand_noalt_rules(syntax)
|
|
||||||
syntax = reorder_rules(syntax)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.remove_underivable_rules(syntax)
|
|
||||||
deribable_syms = {}
|
|
||||||
changed = true
|
|
||||||
while changed
|
|
||||||
changed = false
|
|
||||||
syntax.each {|sym, rules|
|
|
||||||
next if deribable_syms[sym]
|
|
||||||
rules.each {|rhs|
|
|
||||||
if rhs.all? {|e| String === e || deribable_syms[e] }
|
|
||||||
deribable_syms[sym] = true
|
|
||||||
changed = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
result = {}
|
|
||||||
syntax.each {|sym, rules|
|
|
||||||
next if !deribable_syms[sym]
|
|
||||||
rules2 = []
|
|
||||||
rules.each {|rhs|
|
|
||||||
rules2 << rhs if rhs.all? {|e| String === e || deribable_syms[e] }
|
|
||||||
}
|
|
||||||
result[sym] = rules2.uniq
|
|
||||||
}
|
|
||||||
result
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.expand_justempty_rules(syntax)
|
|
||||||
justempty_syms = {}
|
|
||||||
changed = true
|
|
||||||
while changed
|
|
||||||
changed = false
|
|
||||||
syntax.each {|sym, rules|
|
|
||||||
next if justempty_syms[sym]
|
|
||||||
if rules.all? {|rhs| rhs.all? {|e| justempty_syms[e] } }
|
|
||||||
justempty_syms[sym] = true
|
|
||||||
changed = true
|
|
||||||
end
|
|
||||||
}
|
|
||||||
end
|
|
||||||
result = {}
|
|
||||||
syntax.each {|sym, rules|
|
|
||||||
result[sym] = rules.map {|rhs| rhs.reject {|e| justempty_syms[e] } }.uniq
|
|
||||||
}
|
|
||||||
result
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.expand_emptyable_syms(rhs, emptyable_syms)
|
|
||||||
if rhs.empty?
|
|
||||||
elsif rhs.length == 1
|
|
||||||
if emptyable_syms[rhs[0]]
|
|
||||||
yield rhs
|
|
||||||
yield []
|
|
||||||
else
|
|
||||||
yield rhs
|
|
||||||
end
|
|
||||||
else
|
|
||||||
butfirst = rhs[1..-1]
|
|
||||||
if emptyable_syms[rhs[0]]
|
|
||||||
expand_emptyable_syms(butfirst, emptyable_syms) {|rhs2|
|
|
||||||
yield [rhs[0]] + rhs2
|
|
||||||
yield rhs2
|
|
||||||
}
|
|
||||||
else
|
|
||||||
expand_emptyable_syms(butfirst, emptyable_syms) {|rhs2|
|
|
||||||
yield [rhs[0]] + rhs2
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.remove_emptyable_rules(syntax)
|
|
||||||
emptyable_syms = {}
|
|
||||||
changed = true
|
|
||||||
while changed
|
|
||||||
changed = false
|
|
||||||
syntax.each {|sym, rules|
|
|
||||||
next if emptyable_syms[sym]
|
|
||||||
rules.each {|rhs|
|
|
||||||
if rhs.all? {|e| emptyable_syms[e] }
|
|
||||||
emptyable_syms[sym] = true
|
|
||||||
changed = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
result = {}
|
|
||||||
syntax.each {|sym, rules|
|
|
||||||
rules2 = []
|
|
||||||
rules.each {|rhs|
|
|
||||||
expand_emptyable_syms(rhs, emptyable_syms) {|rhs2|
|
|
||||||
rules2 << rhs2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result[sym] = rules2.uniq
|
|
||||||
}
|
|
||||||
result
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.expand_channel_rules(syntax)
|
|
||||||
channel_rules = {}
|
|
||||||
syntax.each {|sym, rules|
|
|
||||||
channel_rules[sym] = {sym=>true}
|
|
||||||
rules.each {|rhs|
|
|
||||||
if rhs.length == 1 && Symbol === rhs[0]
|
|
||||||
channel_rules[sym][rhs[0]] = true
|
|
||||||
end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
changed = true
|
|
||||||
while changed
|
|
||||||
changed = false
|
|
||||||
channel_rules.each {|sym, set|
|
|
||||||
n1 = set.size
|
|
||||||
set.keys.each {|s|
|
|
||||||
set.update(channel_rules[s])
|
|
||||||
}
|
|
||||||
n2 = set.size
|
|
||||||
changed = true if n1 < n2
|
|
||||||
}
|
|
||||||
end
|
|
||||||
result = {}
|
|
||||||
syntax.each {|sym, rules|
|
|
||||||
rules2 = []
|
|
||||||
channel_rules[sym].each_key {|s|
|
|
||||||
syntax[s].each {|rhs|
|
|
||||||
unless rhs.length == 1 && Symbol === rhs[0]
|
|
||||||
rules2 << rhs
|
|
||||||
end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result[sym] = rules2.uniq
|
|
||||||
}
|
|
||||||
result
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.expand_noalt_rules(syntax)
|
|
||||||
noalt_syms = {}
|
|
||||||
syntax.each {|sym, rules|
|
|
||||||
if rules.length == 1
|
|
||||||
noalt_syms[sym] = true
|
|
||||||
end
|
|
||||||
}
|
|
||||||
result = {}
|
|
||||||
syntax.each {|sym, rules|
|
|
||||||
rules2 = []
|
|
||||||
rules.each {|rhs|
|
|
||||||
rhs2 = []
|
|
||||||
rhs.each {|e|
|
|
||||||
if noalt_syms[e]
|
|
||||||
rhs2.concat syntax[e][0]
|
|
||||||
else
|
|
||||||
rhs2 << e
|
|
||||||
end
|
|
||||||
}
|
|
||||||
rules2 << rhs2
|
|
||||||
}
|
|
||||||
result[sym] = rules2.uniq
|
|
||||||
}
|
|
||||||
result
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.reorder_rules(syntax)
|
|
||||||
result = {}
|
|
||||||
syntax.each {|sym, rules|
|
|
||||||
result[sym] = rules.sort_by {|rhs|
|
|
||||||
[rhs.find_all {|e| Symbol === e }.length, rhs.length]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result
|
|
||||||
end
|
|
||||||
|
|
||||||
def each_tree(sym, limit)
|
|
||||||
generate_from_sym(sym, limit) {|_, tree|
|
|
||||||
yield tree
|
|
||||||
}
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def each_string(sym, limit)
|
|
||||||
generate_from_sym(sym, limit) {|_, tree|
|
|
||||||
yield [tree].join('')
|
|
||||||
}
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def generate_from_sym(sym, limit, &b)
|
|
||||||
return if limit < 0
|
|
||||||
if String === sym
|
|
||||||
yield limit, sym
|
|
||||||
else
|
|
||||||
rules = @syntax[sym]
|
|
||||||
raise "undefined rule: #{sym}" if !rules
|
|
||||||
rules.each {|rhs|
|
|
||||||
if rhs.length == 1 || rules.length == 1
|
|
||||||
limit1 = limit
|
|
||||||
else
|
|
||||||
limit1 = limit-1
|
|
||||||
end
|
|
||||||
generate_from_rhs(rhs, limit1, &b)
|
|
||||||
}
|
|
||||||
end
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def generate_from_rhs(rhs, limit)
|
|
||||||
return if limit < 0
|
|
||||||
if rhs.empty?
|
|
||||||
yield limit, []
|
|
||||||
else
|
|
||||||
generate_from_sym(rhs[0], limit) {|limit1, child|
|
|
||||||
generate_from_rhs(rhs[1..-1], limit1) {|limit2, arr|
|
|
||||||
yield limit2, [child, *arr]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def SentGen.subst(obj, target, &b)
|
|
||||||
if obj.respond_to? :to_ary
|
|
||||||
a = []
|
|
||||||
obj.each {|e| a << subst(e, target, &b) }
|
|
||||||
a
|
|
||||||
elsif target === obj
|
|
||||||
yield obj
|
|
||||||
else
|
|
||||||
obj
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
|
@ -490,7 +490,7 @@ class TestAssignment < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
require 'sentgen'
|
require 'sentence'
|
||||||
class TestAssignmentGen < Test::Unit::TestCase
|
class TestAssignmentGen < Test::Unit::TestCase
|
||||||
Syntax = {
|
Syntax = {
|
||||||
:exp => [["0"],
|
:exp => [["0"],
|
||||||
|
@ -537,7 +537,7 @@ class TestAssignmentGen < Test::Unit::TestCase
|
||||||
|
|
||||||
def rename_var(obj)
|
def rename_var(obj)
|
||||||
vars = []
|
vars = []
|
||||||
r = SentGen.subst(obj, 'var') {
|
r = obj.subst('var') {
|
||||||
var = "v#{vars.length}"
|
var = "v#{vars.length}"
|
||||||
vars << var
|
vars << var
|
||||||
var
|
var
|
||||||
|
@ -646,7 +646,7 @@ class TestAssignmentGen < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def do_assign(assign, vars)
|
def do_assign(assign, vars)
|
||||||
assign = assign.join('')
|
assign = assign.to_s
|
||||||
code = "#{assign}; [#{vars.join(",")}]"
|
code = "#{assign}; [#{vars.join(",")}]"
|
||||||
begin
|
begin
|
||||||
vals = eval(code)
|
vals = eval(code)
|
||||||
|
@ -659,12 +659,12 @@ class TestAssignmentGen < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_assignment
|
def test_assignment
|
||||||
syntax = SentGen.expand_syntax(Syntax)
|
syntax = Sentence::Gen.expand_syntax(Syntax)
|
||||||
SentGen.each_tree(syntax, :xassign, 3) {|assign|
|
Sentence.each(syntax, :xassign, 3) {|assign|
|
||||||
assign[0], vars = rename_var(assign[0])
|
assign, vars = rename_var(assign)
|
||||||
sent = [assign].join('')
|
sent = assign.to_s
|
||||||
bruby = do_assign(assign, vars).to_a.sort
|
bruby = do_assign(assign, vars).to_a.sort
|
||||||
bemu = emu_assign(assign).to_a.sort
|
bemu = emu_assign(assign.to_a).to_a.sort
|
||||||
assert_equal(bemu, bruby, sent)
|
assert_equal(bemu, bruby, sent)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
@ -66,7 +66,7 @@ class TestRubyYield < Test::Unit::TestCase
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
require 'sentgen'
|
require 'sentence'
|
||||||
class TestRubyYieldGen < Test::Unit::TestCase
|
class TestRubyYieldGen < Test::Unit::TestCase
|
||||||
Syntax = {
|
Syntax = {
|
||||||
:exp => [["0"],
|
:exp => [["0"],
|
||||||
|
@ -154,12 +154,12 @@ class TestRubyYieldGen < Test::Unit::TestCase
|
||||||
[]],
|
[]],
|
||||||
:block_arg => [['&', :arg]],
|
:block_arg => [['&', :arg]],
|
||||||
#:test => [['def m() yield', :command_args_noblock, ' end; r = m {', :block_param_def, 'vars', '}; undef m; r']]
|
#:test => [['def m() yield', :command_args_noblock, ' end; r = m {', :block_param_def, 'vars', '}; undef m; r']]
|
||||||
:test => [['def m(&b) b.yield', :command_args_noblock, ' end; r = m {', :block_param_def, 'vars', '}; undef m; r']]
|
:test => [['def m() yield', :command_args_noblock, ' end; r = m {', :block_param_def, 'vars', '}; undef m; r']]
|
||||||
}
|
}
|
||||||
|
|
||||||
def rename_var(obj)
|
def rename_var(obj)
|
||||||
vars = []
|
vars = []
|
||||||
r = SentGen.subst(obj, 'var') {
|
r = obj.subst('var') {
|
||||||
var = "v#{vars.length}"
|
var = "v#{vars.length}"
|
||||||
vars << var
|
vars << var
|
||||||
var
|
var
|
||||||
|
@ -167,20 +167,134 @@ class TestRubyYieldGen < Test::Unit::TestCase
|
||||||
return r, vars
|
return r, vars
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def split_by_comma(ary)
|
||||||
|
return [] if ary.empty?
|
||||||
|
result = [[]]
|
||||||
|
ary.each {|e|
|
||||||
|
if e == ','
|
||||||
|
result << []
|
||||||
|
else
|
||||||
|
result.last << e
|
||||||
|
end
|
||||||
|
}
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
def emu_return_args(*vs)
|
||||||
|
vs
|
||||||
|
end
|
||||||
|
|
||||||
|
def emu_eval_args(args)
|
||||||
|
if args.last == []
|
||||||
|
args = args[0...-1]
|
||||||
|
end
|
||||||
|
code = "emu_return_args #{args.map {|a| a.join('') }.join(",")}"
|
||||||
|
eval code
|
||||||
|
end
|
||||||
|
|
||||||
|
def emu_bind_single(arg, param, result_binding)
|
||||||
|
#p [:emu_bind_single, arg, param]
|
||||||
|
if param.length == 1 && String === param[0] && /\A[a-z0-9]+\z/ =~ param[0]
|
||||||
|
result_binding[param[0]] = arg
|
||||||
|
elsif param.length == 1 && Array === param[0] && param[0][0] == '(' && param[0][-1] == ')'
|
||||||
|
arg = [arg] unless Array === arg
|
||||||
|
emu_bind_params(arg, split_by_comma(param[0][1...-1]), result_binding)
|
||||||
|
else
|
||||||
|
raise "unexpected param: #{param.inspect}"
|
||||||
|
end
|
||||||
|
result_binding
|
||||||
|
end
|
||||||
|
|
||||||
|
def emu_bind_params(args, params, result_binding={})
|
||||||
|
#p [:emu_bind_params, args, params]
|
||||||
|
if params.last == [] # extra comma
|
||||||
|
params.pop
|
||||||
|
end
|
||||||
|
|
||||||
|
if params.last && params.last[0] == '&'
|
||||||
|
result_binding[params.last[1]] = nil
|
||||||
|
params.pop
|
||||||
|
end
|
||||||
|
|
||||||
|
star_index = nil
|
||||||
|
params.each_with_index {|par, i|
|
||||||
|
star_index = i if par[0] == '*'
|
||||||
|
}
|
||||||
|
|
||||||
|
# TRICK #2 : adjust mismatch on number of arguments
|
||||||
|
if star_index
|
||||||
|
pre_params = params[0...star_index]
|
||||||
|
rest_param = params[star_index]
|
||||||
|
post_params = params[(star_index+1)..-1]
|
||||||
|
pre_params.each {|par| emu_bind_single(args.shift, par, result_binding) }
|
||||||
|
if post_params.length <= args.length
|
||||||
|
post_params.reverse_each {|par| emu_bind_single(args.pop, par, result_binding) }
|
||||||
|
else
|
||||||
|
post_params.each {|par| emu_bind_single(args.shift, par, result_binding) }
|
||||||
|
end
|
||||||
|
if rest_param != ['*']
|
||||||
|
emu_bind_single(args, rest_param[1..-1], result_binding)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
params.each_with_index {|par, i|
|
||||||
|
emu_bind_single(args[i], par, result_binding)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
#p [args, params, result_binding]
|
||||||
|
|
||||||
|
result_binding
|
||||||
|
end
|
||||||
|
|
||||||
|
def emu(t)
|
||||||
|
#puts
|
||||||
|
#p t
|
||||||
|
command_args_noblock = t[1]
|
||||||
|
block_param_def = t[3]
|
||||||
|
command_args_noblock = command_args_noblock.expand {|a| !(a[0] == '[' && a[-1] == ']') }
|
||||||
|
block_param_def = block_param_def.expand {|a| !(a[0] == '(' && a[-1] == ')') }
|
||||||
|
|
||||||
|
if command_args_noblock.to_a[0] == ' '
|
||||||
|
args = command_args_noblock.to_a[1..-1]
|
||||||
|
elsif command_args_noblock.to_a[0] == '(' && command_args_noblock.to_a[-1] == ')'
|
||||||
|
args = command_args_noblock.to_a[1...-1]
|
||||||
|
else
|
||||||
|
raise "unexpected command_args_noblock: #{command_args_noblock.inspect}"
|
||||||
|
end
|
||||||
|
args = emu_eval_args(split_by_comma(args))
|
||||||
|
|
||||||
|
params = block_param_def.to_a[1...-1]
|
||||||
|
params = split_by_comma(params)
|
||||||
|
|
||||||
|
#p [:emu0, args, params]
|
||||||
|
|
||||||
|
# TRICK #1 : single array argument is expanded if there are two or more params.
|
||||||
|
if args.length == 1 && Array === args[0] && 1 < params.length
|
||||||
|
args = args[0]
|
||||||
|
end
|
||||||
|
|
||||||
|
result_binding = emu_bind_params(args, params)
|
||||||
|
#p result_binding
|
||||||
|
result_binding
|
||||||
|
end
|
||||||
|
|
||||||
def check_nofork(t)
|
def check_nofork(t)
|
||||||
t, vars = rename_var(t)
|
t, vars = rename_var(t)
|
||||||
t = SentGen.subst(t, 'vars') { " [#{vars.join(",")}]" }
|
t = t.subst('vars') { " [#{vars.join(",")}]" }
|
||||||
s = [t].join
|
emu_binding = emu(t)
|
||||||
|
emu_values = vars.map {|var| emu_binding.fetch(var, "NOVAL") }
|
||||||
|
s = t.to_s
|
||||||
#print "#{s}\t\t"
|
#print "#{s}\t\t"
|
||||||
#STDOUT.flush
|
#STDOUT.flush
|
||||||
v = eval(s)
|
eval_values = eval(s)
|
||||||
#puts "#{v.inspect[1...-1]}"
|
#success = emu_values == eval_values ? 'succ' : 'fail'
|
||||||
##xxx: assertion for v here.
|
#puts "eval:#{vs_ev.inspect[1...-1].delete(' ')}\temu:#{vs_emu.inspect[1...-1].delete(' ')}\t#{success}"
|
||||||
|
assert_equal(emu_values, eval_values, s)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_yield
|
def test_yield
|
||||||
syntax = SentGen.expand_syntax(Syntax)
|
syntax = Sentence::Gen.expand_syntax(Syntax)
|
||||||
SentGen.each_tree(syntax, :test, 4) {|t|
|
Sentence.each(syntax, :test, 4) {|t|
|
||||||
check_nofork(t)
|
check_nofork(t)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue