falluto 0.0.1 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/cleantrace.rb +97 -0
- data/bin/falluto.rb +92 -2
- data/bin/ftnusmv.rb +96 -0
- data/bin/viewtrace.rb +162 -0
- data/lib/falluto/compiler.rb +410 -0
- data/lib/falluto/grammar/nodes.rb +141 -0
- data/lib/falluto/grammar/rules.treetop +478 -0
- data/lib/falluto/grammar/tokens.treetop +145 -0
- data/lib/falluto/grammar.rb +7 -0
- data/lib/falluto/nusmv/codegen.rb +39 -0
- data/lib/falluto/nusmv/fault.rb +87 -0
- data/lib/falluto/nusmv/module.rb +45 -0
- data/lib/falluto/nusmv/variable.rb +13 -0
- data/lib/falluto/nusmv.rb +4 -0
- data/lib/falluto/ruby_extensions/class.rb +10 -0
- data/lib/falluto/ruby_extensions/file.rb +5 -0
- data/lib/falluto/ruby_extensions/hash.rb +3 -0
- data/lib/falluto/ruby_extensions/string.rb +5 -0
- data/lib/falluto/ruby_extensions.rb +4 -0
- data/lib/falluto/symboltable.rb +34 -0
- data/lib/falluto/version.rb +10 -0
- data/spec/grammar/parser_spec.rb +121 -0
- data/spec/nusmv/fault_spec.rb +17 -0
- data/spec/nusmv/generator_spec.rb +42 -0
- data/spec/nusmv/module_spec.rb +12 -0
- data/spec/nusmv/variable_spec.rb +32 -0
- data/spec/spec_helper.rb +4 -0
- metadata +35 -14
- data/.document +0 -5
- data/.gitignore +0 -21
- data/Rakefile +0 -56
- data/VERSION +0 -1
- data/test/helper.rb +0 -10
- data/test/test_falluto.rb +0 -7
data/bin/cleantrace.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
|
5
|
+
require 'falluto/ruby_extensions'
|
6
|
+
require 'falluto/version'
|
7
|
+
|
8
|
+
class TraceCleaner
|
9
|
+
def clean tracefile, auxfile, output
|
10
|
+
load_auxdata auxfile
|
11
|
+
do_clean tracefile, output
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def load_auxdata filename
|
17
|
+
@auxvars, @specs = [], []
|
18
|
+
|
19
|
+
IO.foreach(filename) do |line|
|
20
|
+
if line =~ /^VAR: (.*)$/
|
21
|
+
@auxvars << $1.chomp
|
22
|
+
elsif line =~ /^SPEC: (.*)$/
|
23
|
+
@specs << $1.chomp
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def do_clean filename, output
|
29
|
+
varsregexp = @auxvars.join('|')
|
30
|
+
i = 0
|
31
|
+
|
32
|
+
IO.foreach(filename) do |line|
|
33
|
+
if line =~ /^-- specification (.*) is (true|false)/
|
34
|
+
output.puts "Spec: #{@specs[i]} is #{$2}"
|
35
|
+
output.puts "Counterexample:" if $2 == "false"
|
36
|
+
i += 1
|
37
|
+
elsif ((!varsregexp.empty?) && (line =~ /#{varsregexp}/))
|
38
|
+
# skip it
|
39
|
+
elsif (line =~ /-- Loop/) or (line !~ /^(\*\*\*|WARNING|--|Trace|$)/)
|
40
|
+
output.print line
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def parse_cmdline_args
|
47
|
+
options = {:file => nil, :auxfile => nil, :output => nil}
|
48
|
+
optparser = OptionParser.new do |opts|
|
49
|
+
opts.on('-f', '--file <trace_file>', 'Indicate the <trace_file> to be cleaned.') do |file|
|
50
|
+
options[:file] = file
|
51
|
+
end
|
52
|
+
|
53
|
+
opts.on('-a', '--auxfile <aux_file>', 'Indicate the <aux_file> which contains compiler objects.') do |file|
|
54
|
+
options[:auxfile] = file
|
55
|
+
end
|
56
|
+
|
57
|
+
opts.on('-o', '--output <clean_trace>', 'Indicate the output file which will have the clean trace.') do |file|
|
58
|
+
options[:output] = file
|
59
|
+
end
|
60
|
+
|
61
|
+
opts.on('-v', '--version', "Print the version number of #{Falluto::NAME} and exit.") do |x|
|
62
|
+
puts Falluto::Version::STRING
|
63
|
+
exit 0
|
64
|
+
end
|
65
|
+
end
|
66
|
+
optparser.parse!
|
67
|
+
options
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
def main
|
72
|
+
begin
|
73
|
+
options = parse_cmdline_args
|
74
|
+
|
75
|
+
tracefile = options[:file]
|
76
|
+
auxfile = options[:auxfile]
|
77
|
+
cleantrace = options[:output]
|
78
|
+
|
79
|
+
puts "Reading NuSMV trace from: #{tracefile}"
|
80
|
+
puts "Reading support objects from: #{auxfile}"
|
81
|
+
puts "Writing clean trace to: #{cleantrace}"
|
82
|
+
|
83
|
+
cleaner = TraceCleaner.new
|
84
|
+
File.open(cleantrace, "w+") do |output|
|
85
|
+
cleaner.clean tracefile, auxfile, output
|
86
|
+
end
|
87
|
+
|
88
|
+
puts "Done."
|
89
|
+
|
90
|
+
rescue => e
|
91
|
+
puts ""
|
92
|
+
puts "ERROR: #{Falluto::NAME}: #{e} "
|
93
|
+
exit 1
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
main
|
data/bin/falluto.rb
CHANGED
@@ -1,3 +1,93 @@
|
|
1
|
-
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
|
5
|
+
require 'falluto/ruby_extensions'
|
6
|
+
require 'falluto/version'
|
7
|
+
|
8
|
+
def parse_cmdline_args
|
9
|
+
options = {:file => nil}
|
10
|
+
optparser = OptionParser.new do |opts|
|
11
|
+
opts.on('-f', '--file <input_file>', 'Verify the model and specs given in <input_file>.') do |file|
|
12
|
+
options[:file] = file
|
13
|
+
end
|
14
|
+
|
15
|
+
opts.on('-n', '--nusmv <options>', 'Additional options for NuSMV (between quotes).') do |nusmvopts|
|
16
|
+
options[:nusmvopts] = nusmvopts
|
17
|
+
end
|
18
|
+
|
19
|
+
opts.on('-g', '--graph', 'Generate graph of the counterexample automata.') do |x|
|
20
|
+
options[:graph] = true
|
21
|
+
end
|
22
|
+
|
23
|
+
opts.on('-v', '--version', "Print the version number of #{Falluto::NAME} and exit.") do |x|
|
24
|
+
puts Falluto::Version::STRING
|
25
|
+
exit 0
|
26
|
+
end
|
27
|
+
end
|
28
|
+
optparser.parse!
|
29
|
+
options
|
30
|
+
end
|
31
|
+
|
32
|
+
def execute_command cmd
|
33
|
+
puts cmd
|
34
|
+
out = %x{#{cmd}}
|
35
|
+
puts out if out !~ /^$/
|
36
|
+
end
|
37
|
+
|
38
|
+
def compile inputfile, modelfile, auxfile
|
39
|
+
puts "# Compiling..."
|
40
|
+
cmd = "ftnusmv.rb -f #{inputfile} -o #{modelfile} -a #{auxfile}"
|
41
|
+
execute_command cmd
|
42
|
+
end
|
43
|
+
|
44
|
+
def check_model modelfile, tracefile, opts = nil
|
45
|
+
puts "# Model checking..."
|
46
|
+
cmd = "NuSMV #{opts} #{modelfile} > #{tracefile}"
|
47
|
+
execute_command cmd
|
48
|
+
end
|
49
|
+
|
50
|
+
def clean_trace tracefile, auxfile, cleantracefile
|
51
|
+
puts "# Cleaning trace..."
|
52
|
+
cmd = "cleantrace.rb -f #{tracefile} -a #{auxfile} -o #{cleantracefile}"
|
53
|
+
execute_command cmd
|
54
|
+
end
|
55
|
+
|
56
|
+
def generate_automata tracefile, dotfile, pdffile
|
57
|
+
puts "# Graphing automata..."
|
58
|
+
cmd = "viewtrace.rb -f #{tracefile} -d #{dotfile} -o #{pdffile}"
|
59
|
+
execute_command cmd
|
60
|
+
end
|
61
|
+
|
62
|
+
def main
|
63
|
+
begin
|
64
|
+
options = parse_cmdline_args
|
65
|
+
|
66
|
+
inputfile = File.expand_path options[:file]
|
67
|
+
modelfile = File.replace_extension inputfile, 'out'
|
68
|
+
auxfile = File.replace_extension inputfile, 'aux'
|
69
|
+
tracefile = File.replace_extension inputfile, 'trace'
|
70
|
+
cleantracefile = File.replace_extension inputfile, "clean"
|
71
|
+
dotfile = File.replace_extension inputfile, "dot"
|
72
|
+
pdffile = File.replace_extension inputfile, "pdf"
|
73
|
+
|
74
|
+
puts Falluto::Version::STRING
|
75
|
+
puts ""
|
76
|
+
|
77
|
+
compile inputfile, modelfile, auxfile
|
78
|
+
check_model modelfile, tracefile, options[:nusmvopts]
|
79
|
+
clean_trace tracefile, auxfile, cleantracefile
|
80
|
+
|
81
|
+
if options[:graph]
|
82
|
+
generate_automata cleantracefile, dotfile, pdffile
|
83
|
+
end
|
84
|
+
|
85
|
+
rescue OptionParser::InvalidOption => e
|
86
|
+
puts "Falluto: " + e
|
87
|
+
exit 1
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
main
|
92
|
+
|
2
93
|
|
3
|
-
puts "hello world"
|
data/bin/ftnusmv.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
#
|
3
|
+
# FT-NuSMV compiler front end
|
4
|
+
|
5
|
+
require 'optparse' # to build a nicer CLI
|
6
|
+
|
7
|
+
require 'falluto/compiler'
|
8
|
+
require 'falluto/version'
|
9
|
+
|
10
|
+
def parse_cmdline_args
|
11
|
+
options = {:method => :compile, :rule => 'program', :file => nil, :output => nil, :auxfile => nil }
|
12
|
+
op = OptionParser.new do |opts|
|
13
|
+
opts.on('-f', '--file FILE', 'Specify input file') do |f|
|
14
|
+
options[:file] = f
|
15
|
+
end
|
16
|
+
|
17
|
+
opts.on('-o', '--output FILE', 'Specify output file (compiled model)') do |f|
|
18
|
+
options[:output] = f
|
19
|
+
end
|
20
|
+
|
21
|
+
opts.on('-a', '--auxfile FILE', 'Specify auxiliar file (auxiliar variables, etc)') do |f|
|
22
|
+
options[:auxfile] = f
|
23
|
+
end
|
24
|
+
|
25
|
+
opts.on('-v', '--version', "Print the version number of #{Falluto::NAME} and exit.") do |x|
|
26
|
+
puts Falluto::Version::STRING
|
27
|
+
exit 0
|
28
|
+
end
|
29
|
+
end
|
30
|
+
op.parse!
|
31
|
+
options
|
32
|
+
end
|
33
|
+
|
34
|
+
def save_auxiliar_data compiler, filename
|
35
|
+
File.open(filename, "w+") do |f|
|
36
|
+
compiler.auxiliar_variables.each do |v|
|
37
|
+
f.puts "VAR: #{v}"
|
38
|
+
end
|
39
|
+
compiler.specs.each do |s|
|
40
|
+
f.puts "SPEC: #{s}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def save_compiled_code compiler, filename
|
46
|
+
File.open(filename, "w+") do |f|
|
47
|
+
f.puts compiler.compiled_string
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def main
|
52
|
+
begin
|
53
|
+
options = parse_cmdline_args
|
54
|
+
|
55
|
+
infile = options[:file]
|
56
|
+
outfile = options[:output]
|
57
|
+
auxfile = options[:auxfile]
|
58
|
+
|
59
|
+
|
60
|
+
puts "Reading input model from: #{infile}"
|
61
|
+
puts "Writing compiled model to: #{outfile}"
|
62
|
+
puts "Writing support objects to: #{auxfile}"
|
63
|
+
|
64
|
+
string = File.read infile
|
65
|
+
compiler = Compiler.new
|
66
|
+
compiler.run string
|
67
|
+
|
68
|
+
# save compiled string into output file
|
69
|
+
save_compiled_code compiler, outfile
|
70
|
+
|
71
|
+
# save auxiliar data into separate file
|
72
|
+
save_auxiliar_data compiler, auxfile
|
73
|
+
|
74
|
+
puts "Done."
|
75
|
+
|
76
|
+
rescue UndeclaredFault => e
|
77
|
+
puts ""
|
78
|
+
puts "ERROR: Fault #{e} undeclared in module "
|
79
|
+
exit 1
|
80
|
+
rescue RedefinedFault => e
|
81
|
+
puts ""
|
82
|
+
puts "ERROR: Fault #{e} already declared in module "
|
83
|
+
exit 1
|
84
|
+
rescue OptionParser::InvalidOption => e
|
85
|
+
puts ""
|
86
|
+
puts "ERROR: #{e}"
|
87
|
+
exit 1
|
88
|
+
rescue => e
|
89
|
+
puts ""
|
90
|
+
puts "ERROR: #{Falluto::NAME}: #{e}"
|
91
|
+
exit 1
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
main
|
96
|
+
|
data/bin/viewtrace.rb
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
|
5
|
+
require 'falluto/ruby_extensions'
|
6
|
+
require 'falluto/version'
|
7
|
+
|
8
|
+
class Edge
|
9
|
+
def initialize source, dest
|
10
|
+
@source = source
|
11
|
+
@dest = dest
|
12
|
+
@label = ''
|
13
|
+
end
|
14
|
+
def << str
|
15
|
+
@label << str.chomp.strip + '\\n'
|
16
|
+
end
|
17
|
+
def to_dot
|
18
|
+
"#{@source.quote} -> #{@dest.quote} [label=#{@label.quote}];"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class LoopEdge < Edge
|
23
|
+
def to_dot
|
24
|
+
"#{@source.quote} -> #{@dest.quote} [style=dotted,bold label=#{'LOOP'.quote}];"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Node
|
29
|
+
attr_reader :name, :has_loop
|
30
|
+
def initialize name, has_loop
|
31
|
+
@name = name
|
32
|
+
@label = 'State: ' + name + '\\n'
|
33
|
+
@has_loop = has_loop
|
34
|
+
end
|
35
|
+
def << str
|
36
|
+
@label << str.chomp.strip + '\\n'
|
37
|
+
end
|
38
|
+
def to_dot
|
39
|
+
"#{@name.quote} [label=#{@label.quote}];"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class TraceParser
|
44
|
+
def initialize file
|
45
|
+
@nodes = []
|
46
|
+
@edges = []
|
47
|
+
parse file
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_dot
|
51
|
+
"digraph G {\n" +
|
52
|
+
@nodes.collect{|n| n.to_dot + "\n" }.join +
|
53
|
+
@edges.collect{|e| e.to_dot + "\n" }.join +
|
54
|
+
"}\n"
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
def parse file
|
59
|
+
@elems = []
|
60
|
+
node = nil
|
61
|
+
edge = nil
|
62
|
+
has_loop = false
|
63
|
+
IO.foreach(file) do |line|
|
64
|
+
case line
|
65
|
+
when /\*\*\*/
|
66
|
+
# do nothing
|
67
|
+
when /^Trace Description: (.*)/
|
68
|
+
# do nothing
|
69
|
+
when /^Trace Type: (.*)/
|
70
|
+
# do nothing
|
71
|
+
when /-- Loop/
|
72
|
+
has_loop = true
|
73
|
+
when /-> State: (\S+)/
|
74
|
+
node = Node.new $1, has_loop
|
75
|
+
has_loop = false
|
76
|
+
@nodes << node
|
77
|
+
edge = nil
|
78
|
+
when /-> Input: (\S+) /
|
79
|
+
edge = Edge.new node.name, $1
|
80
|
+
@edges << edge
|
81
|
+
node = nil
|
82
|
+
else
|
83
|
+
node <<(line) if node
|
84
|
+
edge <<(line) if edge
|
85
|
+
end
|
86
|
+
end
|
87
|
+
build_loops
|
88
|
+
nil
|
89
|
+
end
|
90
|
+
|
91
|
+
def build_loops
|
92
|
+
source = @nodes.last
|
93
|
+
loop_nodes = @nodes.select {|n| n.has_loop}
|
94
|
+
loop_nodes.each { |dest| @edges << LoopEdge.new(source.name, dest.name) }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
def parse_cmdline_args
|
100
|
+
options = {:file => nil}
|
101
|
+
op = OptionParser.new do |opts|
|
102
|
+
opts.on('-f', '--file <trace_file>', 'Generate the automata for the trace in <trace_file>.') do |file|
|
103
|
+
options[:file] = file
|
104
|
+
end
|
105
|
+
|
106
|
+
opts.on('-d', '--dotfile <dot_file>', 'Save the output dot file to <dot_file>.') do |file|
|
107
|
+
options[:dotfile] = file
|
108
|
+
end
|
109
|
+
|
110
|
+
opts.on('-o', '--output <pdf_file>', 'Save the output PDF to file <pdf_file>.') do |output|
|
111
|
+
options[:pdffile] = output
|
112
|
+
end
|
113
|
+
|
114
|
+
opts.on('-v', '--version', "Print the version number of #{Falluto::NAME} and exit.") do |x|
|
115
|
+
puts Falluto::Version::STRING
|
116
|
+
exit 0
|
117
|
+
end
|
118
|
+
end
|
119
|
+
op.parse!
|
120
|
+
options
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
def dump_dot tracefile, dotfile
|
125
|
+
tp = TraceParser.new tracefile
|
126
|
+
|
127
|
+
File.open(dotfile, "w+") do |f|
|
128
|
+
f.puts tp.to_dot
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def generate_pdf dotfile, pdffile
|
133
|
+
%x{dot -Tpdf #{dotfile} -o #{pdffile}}
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
def main
|
138
|
+
begin
|
139
|
+
options = parse_cmdline_args
|
140
|
+
|
141
|
+
tracefile = options[:file]
|
142
|
+
dotfile = options[:dotfile]
|
143
|
+
pdffile = options[:pdffile]
|
144
|
+
|
145
|
+
puts "Reading clean trace from: #{tracefile}"
|
146
|
+
puts "Writing dot file to: #{dotfile}"
|
147
|
+
puts "Writing automata to: #{pdffile}"
|
148
|
+
|
149
|
+
dump_dot tracefile, dotfile
|
150
|
+
generate_pdf dotfile, pdffile
|
151
|
+
|
152
|
+
puts "Done."
|
153
|
+
|
154
|
+
rescue => e
|
155
|
+
puts ""
|
156
|
+
puts "ERROR: #{Falluto::NAME}: #{e} "
|
157
|
+
puts e.backtrace.join("\n")
|
158
|
+
exit 1
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
main
|