falluto 0.0.1 → 0.0.9
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/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
|