Ruby
FLOWer

FLOWer interpreter on Ruby

More than 5 years have passed since last update.

Usage: flower.rb [<] flower.json

※flower.jsonはダウンロードしたzipを展開すると取り出せます。

本家FLOWerのジョブの3割ほどをカバーしています。

挙動については私の類推です。

条件分岐はドキュメントがないため実装できませんでした。。

複数のジョブから一度に値を受け取った時は先に生成されたジョブから受け取った値を先に使用するという挙動は再現出来ているはずです。


flower.rb

#!/usr/bin/ruby

require 'json'

#FLOWer Job parent
class FLOWerJob
def initialize(jobs,inputports,constant,outputports)
@jobs=jobs # fixme
@queue=Hash.new{|h,k|h[k]=[]}
@inputports=inputports
@constant=constant
@outputports=outputports
@input={}
@constant.each{|k,v|
@input[k]=v
}
end
def send_value(port,value)
@queue[port]<< value
end
def accept_value
@queue.each{|k,v|
if @input[k]==nil && v.size>0
@input[k]=v.shift
end
}
end
def query
return if @inputports.any?{|e|@input[e]==nil}
query2
@inputports.each{|e|
@input[e]=nil if !@constant.has_key?(e)
}
end
end

#FLOWer Jobs
#core
class FLOWerJob_core_Through <FLOWerJob
def query2
value=@input['input']
@outputports['output'].each{|job,port|
@jobs[job].send_value(port,value)
}
end
end
class FLOWerJob_core_Add <FLOWerJob
def query2
value=@input['input1']+@input['input2']
@outputports['output'].each{|job,port|
@jobs[job].send_value(port,value)
}
end
end
class FLOWerJob_core_Times <FLOWerJob
def query2
value=@input['input1']*@input['input2']
@outputports['output'].each{|job,port|
@jobs[job].send_value(port,value)
}
end
end
class FLOWerJob_core_And <FLOWerJob
def query2
value=@input['input1']&@input['input2']
@outputports['output'].each{|job,port|
@jobs[job].send_value(port,value)
}
end
end
class FLOWerJob_core_Or <FLOWerJob
def query2
value=@input['input1']|@input['input2']
@outputports['output'].each{|job,port|
@jobs[job].send_value(port,value)
}
end
end
class FLOWerJob_core_Transistor <FLOWerJob
def query2
value=@input['emitter']
@outputports['collector'].each{|job,port|
@jobs[job].send_value(port,value)
}
end
end
#number
class FLOWerJob_number_C0 <FLOWerJob
def query2
value=0
@outputports['0'].each{|job,port|
@jobs[job].send_value(port,value)
}
end
end
class FLOWerJob_number_C1 <FLOWerJob
def query2
value=1
@outputports['1'].each{|job,port|
@jobs[job].send_value(port,value)
}
end
end
class FLOWerJob_number_C2 <FLOWerJob
def query2
value=2
@outputports['2'].each{|job,port|
@jobs[job].send_value(port,value)
}
end
end
class FLOWerJob_number_C3 <FLOWerJob
def query2
value=3
@outputports['3'].each{|job,port|
@jobs[job].send_value(port,value)
}
end
end
class FLOWerJob_number_C4 <FLOWerJob
def query2
value=4
@outputports['4'].each{|job,port|
@jobs[job].send_value(port,value)
}
end
end
class FLOWerJob_number_C5 <FLOWerJob
def query2
value=5
@outputports['5'].each{|job,port|
@jobs[job].send_value(port,value)
}
end
end
class FLOWerJob_number_C6 <FLOWerJob
def query2
value=6
@outputports['6'].each{|job,port|
@jobs[job].send_value(port,value)
}
end
end
class FLOWerJob_number_C7 <FLOWerJob
def query2
value=7
@outputports['7'].each{|job,port|
@jobs[job].send_value(port,value)
}
end
end
class FLOWerJob_number_C8 <FLOWerJob
def query2
value=8
@outputports['8'].each{|job,port|
@jobs[job].send_value(port,value)
}
end
end
class FLOWerJob_number_C9 <FLOWerJob
def query2
value=9
@outputports['9'].each{|job,port|
@jobs[job].send_value(port,value)
}
end
end
#math
class FLOWerJob_math_Abs <FLOWerJob
def query2
value=@input['input'].abs
@outputports['output'].each{|job,port|
@jobs[job].send_value(port,value)
}
end
end
class FLOWerJob_math_Max <FLOWerJob
def query2
value=[@input['a'],@input['b']].max
@outputports['output'].each{|job,port|
@jobs[job].send_value(port,value)
}
end
end
class FLOWerJob_math_Max <FLOWerJob
def query2
value=[@input['a'],@input['b']].min
@outputports['output'].each{|job,port|
@jobs[job].send_value(port,value)
}
end
end
#system
class FLOWerJob_system_Speed <FLOWerJob
def query2
value=@input['speed']
# do nothing here
@outputports['output'].each{|job,port|
@jobs[job].send_value(port,value)
}
end
end
class FLOWerJob_system_Print <FLOWerJob
def query2
value=@input['input']
print value.to_s+', '
@outputports['output'].each{|job,port|
@jobs[job].send_value(port,value)
}
end
end
class FLOWerJob_system_Scan <FLOWerJob
def query2
#value=@input['input']
print 'input> '
value=gets.to_i
@outputports['output'].each{|job,port|
@jobs[job].send_value(port,value)
}
end
end
#snapsvg
#snapelement
#map
#string
#array

#flower.json runner
class FLOWer
def initialize(json_str)
json=JSON.parse(json_str)
@jobs={}
json['diagram']['jobs'].each{|e|
id=e['id']
constant={}
inputports=[]
e['inputports'].each{|f|
inputports<<f['name']
if f['constant']
constant[f['name']]=f['constant']['value']
end
}
if e['ref']
ref=e['ref']
else
ref='core.Through'
inputports=['input']
@entry=id
end
outputports={}
e['outputports'].map{|f|
outputports[f['name']]=f['connections'].map{|e|e.split('.')}
}
#If NameError is thrown here, that means the job is not implemented yet.
@jobs[id]=Object.const_get('FLOWerJob_'+ref.gsub('.','_')).new(@jobs,inputports,constant,outputports)
}
end
def run
@jobs[@entry].send_value('input',0)
@jobs[@entry].accept_value
loop{
@jobs.each{|k,v|
v.query
}
@jobs.each{|k,v|
v.accept_value
}
}
end
end
FLOWer.new($<.read).run