pg-verify 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/Gemfile +10 -0
  4. data/Gemfile.lock +98 -0
  5. data/README.md +29 -0
  6. data/Rakefile +62 -0
  7. data/bin/console +15 -0
  8. data/bin/pg-verify.rb +18 -0
  9. data/bin/setup +8 -0
  10. data/calc.ebnf +21 -0
  11. data/data/config/pg-verify.yml +66 -0
  12. data/data/nusmv.sample.smv +179 -0
  13. data/data/project-template/.gitignore.resource +4 -0
  14. data/data/project-template/.pg-verify.yml +0 -0
  15. data/data/project-template/README.md +18 -0
  16. data/data/project-template/addon/.keep +0 -0
  17. data/data/project-template/program-graph.rb.resource +103 -0
  18. data/devpg +5 -0
  19. data/doc/examples/railroad_crossing.rb +61 -0
  20. data/doc/examples/train-tree.rb +43 -0
  21. data/doc/examples/weidezaun.rb +99 -0
  22. data/doc/examples/weidezaun.txt +29 -0
  23. data/doc/expose/definition.png +0 -0
  24. data/doc/expose/diagram.png +0 -0
  25. data/doc/expose/expose.md +359 -0
  26. data/doc/expose/validity.png +0 -0
  27. data/exe/pg-verify +4 -0
  28. data/integration_tests/ruby_dsl/001_states.rb +10 -0
  29. data/integration_tests/ruby_dsl/002_transitions.rb +10 -0
  30. data/integration_tests/ruby_dsl/003_actions.rb +14 -0
  31. data/integration_tests/ruby_dsl/004_guards.rb +18 -0
  32. data/integration_tests/ruby_dsl/005_variables.rb +16 -0
  33. data/integration_tests/ruby_dsl/006_state_variables.rb +26 -0
  34. data/integration_tests/ruby_dsl/007_variable_initialization.rb +28 -0
  35. data/integration_tests/ruby_dsl/008_state_initialization.rb +19 -0
  36. data/integration_tests/ruby_dsl/009_shared_variables.rb +26 -0
  37. data/integration_tests/ruby_dsl/010_complex_guards.rb +18 -0
  38. data/integration_tests/ruby_dsl/011_complex_actions.rb +16 -0
  39. data/integration_tests/ruby_dsl/012_error_components.rb +9 -0
  40. data/integration_tests/ruby_dsl/013_hazards.rb +25 -0
  41. data/integration_tests/ruby_dsl/014_tau_transitions.rb +26 -0
  42. data/integration_tests/ruby_dsl/015_basic_dcca.rb +19 -0
  43. data/integration_tests/ruby_dsl/016_pressure_tank.rb +146 -0
  44. data/lib/pg-verify/cli/cli.rb +235 -0
  45. data/lib/pg-verify/core/cmd_runner.rb +151 -0
  46. data/lib/pg-verify/core/core.rb +38 -0
  47. data/lib/pg-verify/core/extensions/array_extensions.rb +11 -0
  48. data/lib/pg-verify/core/extensions/enumerable_extensions.rb +19 -0
  49. data/lib/pg-verify/core/extensions/nil_extensions.rb +7 -0
  50. data/lib/pg-verify/core/extensions/string_extensions.rb +84 -0
  51. data/lib/pg-verify/core/shell/colorizer.rb +136 -0
  52. data/lib/pg-verify/core/shell/shell.rb +0 -0
  53. data/lib/pg-verify/core/util.rb +146 -0
  54. data/lib/pg-verify/doctor/doctor.rb +180 -0
  55. data/lib/pg-verify/ebnf_parser/ast.rb +31 -0
  56. data/lib/pg-verify/ebnf_parser/ebnf_parser.rb +26 -0
  57. data/lib/pg-verify/ebnf_parser/expression_parser.rb +177 -0
  58. data/lib/pg-verify/ebnf_parser/expression_parser2.rb +422 -0
  59. data/lib/pg-verify/ebnf_parser/expressions.ebnf +33 -0
  60. data/lib/pg-verify/ebnf_parser/expressions.peg +52 -0
  61. data/lib/pg-verify/ebnf_parser/parser_result.rb +26 -0
  62. data/lib/pg-verify/interpret/component_context.rb +125 -0
  63. data/lib/pg-verify/interpret/graph_context.rb +85 -0
  64. data/lib/pg-verify/interpret/interpret.rb +142 -0
  65. data/lib/pg-verify/interpret/pg_script.rb +72 -0
  66. data/lib/pg-verify/interpret/spec/ltl_builder.rb +90 -0
  67. data/lib/pg-verify/interpret/spec/spec_context.rb +32 -0
  68. data/lib/pg-verify/interpret/spec/spec_set_context.rb +67 -0
  69. data/lib/pg-verify/interpret/transition_context.rb +55 -0
  70. data/lib/pg-verify/model/allocation_set.rb +28 -0
  71. data/lib/pg-verify/model/assignment.rb +34 -0
  72. data/lib/pg-verify/model/component.rb +40 -0
  73. data/lib/pg-verify/model/dcca/hazard.rb +16 -0
  74. data/lib/pg-verify/model/dcca.rb +67 -0
  75. data/lib/pg-verify/model/expression.rb +106 -0
  76. data/lib/pg-verify/model/graph.rb +58 -0
  77. data/lib/pg-verify/model/model.rb +10 -0
  78. data/lib/pg-verify/model/parsed_expression.rb +77 -0
  79. data/lib/pg-verify/model/simulation/trace.rb +43 -0
  80. data/lib/pg-verify/model/simulation/variable_state.rb +23 -0
  81. data/lib/pg-verify/model/source_location.rb +45 -0
  82. data/lib/pg-verify/model/specs/spec.rb +44 -0
  83. data/lib/pg-verify/model/specs/spec_result.rb +25 -0
  84. data/lib/pg-verify/model/specs/spec_set.rb +43 -0
  85. data/lib/pg-verify/model/specs/specification.rb +50 -0
  86. data/lib/pg-verify/model/transition.rb +41 -0
  87. data/lib/pg-verify/model/validation/assignment_to_state_variable_validation.rb +26 -0
  88. data/lib/pg-verify/model/validation/empty_state_set_validation.rb +18 -0
  89. data/lib/pg-verify/model/validation/errors.rb +119 -0
  90. data/lib/pg-verify/model/validation/foreign_assignment_validation.rb +30 -0
  91. data/lib/pg-verify/model/validation/unknown_token_validation.rb +35 -0
  92. data/lib/pg-verify/model/validation/validation.rb +23 -0
  93. data/lib/pg-verify/model/variable.rb +47 -0
  94. data/lib/pg-verify/model/variable_set.rb +84 -0
  95. data/lib/pg-verify/nusmv/nusmv.rb +23 -0
  96. data/lib/pg-verify/nusmv/runner.rb +124 -0
  97. data/lib/pg-verify/puml/puml.rb +23 -0
  98. data/lib/pg-verify/shell/loading/line_animation.rb +36 -0
  99. data/lib/pg-verify/shell/loading/loading_animation.rb +80 -0
  100. data/lib/pg-verify/shell/loading/loading_prompt.rb +43 -0
  101. data/lib/pg-verify/shell/loading/no_animation.rb +20 -0
  102. data/lib/pg-verify/shell/shell.rb +30 -0
  103. data/lib/pg-verify/simulation/simulation.rb +7 -0
  104. data/lib/pg-verify/simulation/simulator.rb +90 -0
  105. data/lib/pg-verify/simulation/state.rb +53 -0
  106. data/lib/pg-verify/transform/hash_transformation.rb +104 -0
  107. data/lib/pg-verify/transform/nusmv_transformation.rb +261 -0
  108. data/lib/pg-verify/transform/puml_transformation.rb +89 -0
  109. data/lib/pg-verify/transform/transform.rb +8 -0
  110. data/lib/pg-verify/version.rb +5 -0
  111. data/lib/pg-verify.rb +47 -0
  112. data/pg-verify.gemspec +38 -0
  113. data/sig/pg-verify.rbs +4 -0
  114. metadata +226 -0
@@ -0,0 +1,85 @@
1
+
2
+ module PgVerify
3
+ module Interpret
4
+
5
+ class GraphContext
6
+
7
+ attr_accessor :parent_script
8
+ # The list of currently declared components
9
+ attr_accessor :components
10
+ attr_accessor :specs
11
+ attr_accessor :hazards
12
+ # The name of this graph
13
+ attr_accessor :name
14
+
15
+ def initialize(name, parent_script)
16
+ @parent_script = parent_script
17
+ @name = name
18
+ @components, @specs, @hazards = [], [], []
19
+ end
20
+
21
+ # DSL method for declaring a new component in this graph
22
+ def graph(name, &blk)
23
+ raise InvalidDSL_graph.new("Name '#{name}' is neither a symbol nor string") unless name.is_a?(Symbol) || name.is_a?(String)
24
+ cmp = ComponentContext.new(name, self)
25
+ cmp.instance_eval(&blk)
26
+ @components << cmp
27
+ return cmp
28
+ end
29
+
30
+ def transient(name)
31
+ cmp = graph(name) do
32
+ all_states = [ :No, :Yes ]
33
+ states(*all_states)
34
+ all_states.product(all_states).each { |s1, s2| transition({ s1 => s2}) }
35
+ end
36
+ cmp.represents_fault = true
37
+ return cmp
38
+ end
39
+
40
+ def persistent(name)
41
+ cmp = graph(name) do
42
+ states(:No, :Yes)
43
+ transition :No => :No
44
+ transition :No => :Yes
45
+ end
46
+ cmp.represents_fault = true
47
+ return cmp
48
+ end
49
+
50
+ def disable_error(name)
51
+ cmp = @components.find { |c| c.name == name.to_sym }
52
+ raise "No such component: #{name}" if cmp.nil?
53
+ raise "Not an error component: #{name}" unless cmp.represents_fault
54
+ cmp.transition_list = [ ]
55
+ cmp.init_expressions = [ "#{name} == No" ]
56
+ end
57
+
58
+ def error(name)
59
+ return name
60
+ end
61
+
62
+ # DSL method for declaring a new specification in this graph
63
+ def specify(text, &blk)
64
+ specset = SpecSetContext.new(text, self, nil)
65
+ specset.instance_eval(&blk)
66
+ @specs << specset
67
+ end
68
+
69
+ def hazard(hash)
70
+ text = hash.keys.first
71
+ expression = hash[text]
72
+ @hazards << Model::Hazard.new(text, expression)
73
+ end
74
+
75
+ def to_model()
76
+ components = @components.map(&:to_model)
77
+ variables = Model::VariableSet.new(*@components.map(&:owned_variables).flatten())
78
+ specification = Model::Specification.new(@specs.map { |s| s.to_model(nil) })
79
+ Model::Graph.new(@name, components: components, variables: variables, specification: specification, hazards: @hazards)
80
+ end
81
+
82
+ end
83
+
84
+ end
85
+ end
@@ -0,0 +1,142 @@
1
+ # Require all module files
2
+ Dir[File.join(__dir__, "**", '*.rb')].sort.each { |file| require file }
3
+
4
+ module PgVerify
5
+
6
+ module Interpret
7
+
8
+ class InterpretError < PgVerify::Core::Error
9
+ attr_accessor :script_file
10
+ attr_accessor :line_number
11
+ attr_accessor :cause
12
+
13
+ def initialize(script_file, line_number, cause)
14
+ @script_file, @line_number, @cause = script_file, line_number, cause
15
+ end
16
+
17
+ def formatted()
18
+ title = "Error while interpreting script at #{@script_file}:#{@line_number}"
19
+ cause_str = format_cause()
20
+
21
+ sloc = Model::SourceLocation.new(@script_file, @line_number)
22
+ code_block = sloc.render_code_block
23
+
24
+ body = "#{code_block}\n\n#{cause_str}"
25
+ return title, body
26
+ end
27
+
28
+ def format_cause()
29
+ return "#{cause}" unless cause.is_a?(Core::Error)
30
+ return cause.to_formatted()
31
+ end
32
+
33
+ end
34
+
35
+ class InvalidDSL_var < PgVerify::Core::Error
36
+ def initialize(message)
37
+ @message = message
38
+ end
39
+ def formatted()
40
+ hint = [ "Define variables like this:" ]
41
+ hint << "var <name>: <range> [, init: <condition>]"
42
+ hint << " where:"
43
+ hint << " <name> is the name of the variable"
44
+ hint << " <range> is a range of integers like (0..15) or an array of symbols like [ :yes, :no ]"
45
+ hint << " <condition> is either a value in that range or an expression"
46
+ return @message, nil, hint.join("\n")
47
+ end
48
+ end
49
+
50
+ class InvalidDSL_state < PgVerify::Core::Error
51
+ def initialize(message)
52
+ @message = message
53
+ end
54
+ def formatted()
55
+ hint = [ "Define states like this:" ]
56
+ hint << "states <states>"
57
+ hint << " where:"
58
+ hint << " <states> is an array of symbols like :on, :off"
59
+ return @message, nil, hint.join("\n")
60
+ end
61
+ end
62
+
63
+ class InvalidDSL_graph < PgVerify::Core::Error
64
+ def initialize(message)
65
+ @message = message
66
+ end
67
+ def formatted()
68
+ hint = [ "Define graphs like this:" ]
69
+ hint << "graph <name> do ... end"
70
+ return @message, nil, hint.join("\n")
71
+ end
72
+ end
73
+
74
+ class InvalidDSL_transition < PgVerify::Core::Error
75
+ def initialize(message)
76
+ @message = message
77
+ end
78
+ def formatted()
79
+ hint = [ "Define transitions like this:" ]
80
+ hint << "transition <pre-state> => <post-state> do ... end"
81
+ hint << " where"
82
+ hint << " <pre-state> & <post-state> are states in this graph, like :on or :off"
83
+ return @message, nil, hint.join("\n")
84
+ end
85
+ end
86
+
87
+ class InvalidDSL_expression < PgVerify::Core::Error
88
+ def initialize(type, message)
89
+ @type, @message = type, message
90
+ end
91
+ def formatted()
92
+ hint = [ "Define #{@type}s like this:" ]
93
+ hint << "#{@type} <expression>"
94
+ hint << " where"
95
+ hint << " <expression> is a valid expression as a string or symbol"
96
+ return @message, nil, hint.join("\n")
97
+ end
98
+ end
99
+
100
+ class InvalidDSL_model < PgVerify::Core::Error
101
+ def initialize(type, message)
102
+ @type, @message = type, message
103
+ end
104
+ def formatted()
105
+ hint = [ "Define models like this:" ]
106
+ hint << "model <name> do ... end"
107
+ hint << " where"
108
+ hint << " <name> is a string or symbol"
109
+ return @message, nil, hint.join("\n")
110
+ end
111
+ end
112
+
113
+ class NoSuchStateError < PgVerify::Core::Error
114
+ def initialize(state, component)
115
+ @state, @component = state, component
116
+ end
117
+ def formatted()
118
+ title = "No such state #{@state} in component #{@component.name}"
119
+ body = "The component #{@component.name.to_s.c_cmp} does not contain a state called #{@state.to_s.c_state}.\n"
120
+ body += "Available states are: #{@component.states.map(&:to_s).map(&:c_state).join(', ')}"
121
+ hint = "Make sure to define states before defining transitions."
122
+ return title, body, hint
123
+ end
124
+ end
125
+
126
+ class NoSuchScriptError < Core::Error
127
+ def initialize(script_path)
128
+ @script_path = script_path
129
+ end
130
+
131
+ def formatted()
132
+ title = "Could not find script at #{@script_path}"
133
+ body = "No script file at #{@script_path.c_error}!"
134
+ hint = "Make sure to create a program graph script at \n#{File.expand_path(@script_path)}"
135
+ return title, body, hint
136
+ end
137
+
138
+ end
139
+
140
+ end
141
+
142
+ end
@@ -0,0 +1,72 @@
1
+
2
+ module PgVerify
3
+ module Interpret
4
+
5
+ class PgScript
6
+
7
+ # List of models which are defined in this script
8
+ attr_accessor :models
9
+ # The full path to the source script file
10
+ attr_accessor :script_file
11
+
12
+
13
+ def initialize()
14
+ @models = []
15
+ end
16
+
17
+ def interpret(file, validate: true)
18
+ file = File.expand_path(file)
19
+ raise NoSuchScriptError.new(file) unless File.file?(file)
20
+ @script_file ||= file
21
+
22
+ begin
23
+ Dir.chdir(File.dirname(file)) { eval(File.read(file), get_binding(), file) }
24
+ rescue Exception => e
25
+ re_raise_exception(file, self, e)
26
+ end
27
+
28
+ @models.each { |model| Model::Validation.validate!(model) } if validate
29
+
30
+ return @models
31
+ end
32
+
33
+ def model(name, &blk)
34
+ raise InvalidDSL_model.new("Name '#{name}' is neither a symbol nor string") unless name.is_a?(Symbol) || name.is_a?(String)
35
+ graph_ctx = Interpret::GraphContext.new(name.to_sym, self)
36
+ graph_ctx.instance_eval(&blk)
37
+ @models << graph_ctx.to_model()
38
+ end
39
+
40
+ # Re-raise an exception which occurred during evaluation of a script to more user
41
+ # friendly error messages.
42
+ def re_raise_exception(file, script, ex)
43
+ # Determine the line in the script file where the error was raised
44
+ line_number = find_source_location(ex.backtrace).line_number
45
+
46
+ # Include the full backtrace in the message if enabled
47
+ if Settings.full_stack_trace
48
+ title = "Here is the full backtrace of the exception!".c_sidenote + "\n"
49
+ title += "(You don't have to bother with this unless you are developing pg-verify)".c_sidenote
50
+ bt = ex.backtrace.map(&:c_sidenote).join("\n").indented(str: ">> ".c_sidenote)
51
+ end
52
+
53
+ raise InterpretError.new(file, line_number, ex)
54
+ end
55
+ private :re_raise_exception
56
+
57
+ def find_source_location(trace = caller())
58
+ line_number = trace
59
+ .select { |l| l.include?(@script_file) }
60
+ .map { |l| l.split(":in")[0] }.reject(&:blank?)
61
+ .map { |l| l.split(":")[-1] }.reject(&:blank?)
62
+ .uniq.first.to_i
63
+ Model::SourceLocation.new(@script_file, line_number)
64
+ end
65
+
66
+ def get_binding()
67
+ binding()
68
+ end
69
+
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,90 @@
1
+ module PgVerify
2
+ module Interpret
3
+
4
+ class LTLBuilder
5
+
6
+ def globally()
7
+ return LTLBuilderGlobally.new()
8
+ end
9
+ def after(expression)
10
+ return LTLBuilderAfter.new(expression)
11
+ end
12
+ def before(expression)
13
+ LTLBuilderBefore.new(expression)
14
+ end
15
+ def between(); end
16
+ def after_until(); end
17
+
18
+ class LTLBuilderBase
19
+
20
+ def build(pattern, map)
21
+ map.each { |key, val|
22
+ pattern = pattern.gsub(key.to_s, "#{val}")
23
+ }
24
+ return pattern
25
+ end
26
+
27
+ end
28
+
29
+ class LTLBuilderGlobally < LTLBuilderBase
30
+ def global(p)
31
+ build "G p", { p: p }
32
+ end
33
+ def never(p)
34
+ build "G !( p )", { p: p }
35
+ end
36
+ def exists(p)
37
+ build "F p", { p: p }
38
+ end
39
+ def reacts(p, s)
40
+ build "G ( p => F s )", { p: p, s: s }
41
+ end
42
+ def precedes(p, s)
43
+ build "!(p) W s", { p: p, s: s }
44
+ end
45
+ end
46
+
47
+ class LTLBuilderAfter < LTLBuilderBase
48
+ attr_accessor :q
49
+ def initialize(q); @q = q end
50
+ def global(p)
51
+ build "G ( q -> G p )", { p: p, q: q }
52
+ end
53
+ def never(p)
54
+ build "G ( q -> G !(p))", { p: p, q: q }
55
+ end
56
+ def exists(p)
57
+ build "( G !(q) ) || ( F ( q && F p ) )", { p: p, q: q }
58
+ end
59
+ def reacts(p, s)
60
+ build "G ( q => G (p => F s) )", { p: p, q: q, s: s}
61
+ end
62
+ def precedes(p, s)
63
+ build "G !(q) || F ( q && !(p) W s )", { p: p, q: q, s: s}
64
+ end
65
+ end
66
+
67
+ class LTLBuilderBefore < LTLBuilderBase
68
+ attr_accessor :q
69
+ def initialize(q); @q = q end
70
+ def global(p)
71
+
72
+ end
73
+ def never(p)
74
+ build "( F q ) => ( !(p) U q )", { p: p, q: q }
75
+ end
76
+ def exists(p)
77
+
78
+ end
79
+ def reacts(p, s)
80
+
81
+ end
82
+ def precedes(p, s)
83
+
84
+ end
85
+ end
86
+
87
+ end
88
+
89
+ end
90
+ end
@@ -0,0 +1,32 @@
1
+ module PgVerify
2
+ module Interpret
3
+
4
+ class SpecContext
5
+ # The text of this spec as a string.
6
+ attr_accessor :text
7
+
8
+ # The LTL/CTL expression of this spec
9
+ attr_accessor :expression
10
+
11
+ # The parent set of this spec
12
+ attr_accessor :parent
13
+
14
+ attr_accessor :source_location
15
+
16
+ def initialize(text, expression, parent)
17
+ @text, @expression, @parent = text, expression, parent
18
+ @expression = Model::ParsedExpression.new(expression, Model::ParsedExpression::TYPE_TL)
19
+ @expression.source_location = parent.parent_graph.parent_script.find_source_location()
20
+ @source_location = parent.parent_graph.parent_script.find_source_location()
21
+ end
22
+
23
+ def to_model(parent)
24
+ spec = Model::Spec.new(@text, @expression, parent)
25
+ spec.source_location = @source_location
26
+ return spec
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,67 @@
1
+ module PgVerify
2
+ module Interpret
3
+
4
+ class SpecSetContext
5
+
6
+ # The text of this spec set as a string.
7
+ attr_accessor :text
8
+
9
+ # The sub-spec sets contained in this spec set
10
+ attr_accessor :children
11
+
12
+ attr_accessor :parent
13
+
14
+ attr_accessor :assumption
15
+
16
+ attr_accessor :parent_graph
17
+
18
+ attr_accessor :source_location
19
+
20
+ def initialize(text, parent_graph, parent, children = [])
21
+ @text, @parent, @children = text, parent, children
22
+ @parent_graph = parent_graph
23
+ @source_location = parent_graph.parent_script.find_source_location()
24
+ end
25
+
26
+ def specify(text, &blk)
27
+ subset = SpecSetContext.new(text, @parent_graph, self)
28
+ subset.instance_eval(&blk)
29
+ children << subset
30
+ end
31
+
32
+ def assuming(hash, &blk)
33
+ assumption_text = hash.keys.first
34
+ assumption_expression = hash.values.first
35
+ subset = SpecSetContext.new("", @parent_graph, self)
36
+ subset.assumption = { text: assumption_text, expression: assumption_expression }
37
+ subset.instance_eval(&blk)
38
+ children << subset
39
+ end
40
+
41
+ def no_errors()
42
+ err_graphs = @parent_graph.components.select(&:represents_fault)
43
+ expression = err_graphs.map { |g| "#{g.name} == No" }.join(" && ")
44
+ return { "there are no errors" => "G ( #{expression} )" }
45
+ end
46
+
47
+ def it(hash)
48
+ # TODO: Handle errors
49
+ text = hash.keys.first
50
+ expression = hash[text]
51
+ children << SpecContext.new(text, expression.to_s, self)
52
+ end
53
+
54
+ def ltl()
55
+ return LTLBuilder.new()
56
+ end
57
+
58
+ def to_model(parent)
59
+ model = Model::SpecSet.new(@text, @assumption, parent, [])
60
+ model.children = @children.map { |child| child.to_model(model) }
61
+ return model
62
+ end
63
+
64
+ end
65
+ end
66
+
67
+ end
@@ -0,0 +1,55 @@
1
+ module PgVerify
2
+ module Interpret
3
+
4
+ class TransitionContext
5
+
6
+ TempExpression = Struct.new(:string, :source_location)
7
+
8
+ # Back-reference to the component which owns this transition
9
+ attr_accessor :parent_component
10
+
11
+ # Source and target states as symbols
12
+ attr_accessor :src_state, :tgt_state
13
+
14
+ # Strings for the guars, actions and preconditions
15
+ attr_accessor :guard, :action, :precon
16
+
17
+ # Source location for this transition
18
+ attr_accessor :source_location
19
+
20
+ def initialize(parent_component, src_state, tgt_state)
21
+ @parent_component = parent_component
22
+ @src_state, @tgt_state = src_state, tgt_state
23
+ @source_location = @parent_component.parent_graph.parent_script.find_source_location()
24
+ end
25
+
26
+ def guard(str)
27
+ raise "Guard was already defined!" unless @guard.nil?
28
+ raise InvalidDSL_expression.new("guard", "Expression is neither a sting, nor symbol: #{str}") unless str.is_a?(String) | str.is_a?(Symbol)
29
+ @guard = Model::ParsedExpression.new(str, Model::ParsedExpression::TYPE_GUARD)
30
+ @guard.source_location = @parent_component.parent_graph.parent_script.find_source_location()
31
+ end
32
+
33
+ def action(str)
34
+ raise "Action was already defined!" unless @action.nil?
35
+ raise InvalidDSL_expression.new("action", "Expression is neither a sting, nor symbol: #{str}") unless str.is_a?(String) | str.is_a?(Symbol)
36
+ @action = Model::ParsedExpression.new(str, Model::ParsedExpression::TYPE_ACTION)
37
+ @action.source_location = @parent_component.parent_graph.parent_script.find_source_location()
38
+ end
39
+
40
+ def precon(str)
41
+ raise "Precondition was already defined!" unless @guard.nil?
42
+ raise InvalidDSL_expression.new("precon", "Expression is neither a sting, nor symbol: #{str}") unless str.is_a?(String) | str.is_a?(Symbol)
43
+ @precon = Model::ParsedExpression.new(str, Model::ParsedExpression::TYPE_GUARD)
44
+ @precon.source_location = @parent_component.parent_graph.parent_script.find_source_location()
45
+ end
46
+
47
+ def to_model()
48
+ Model::Transition.new(@src_state, @tgt_state, action: @action, precon: @precon, guard: @guard)
49
+ end
50
+
51
+
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,28 @@
1
+ module PgVerify
2
+ module Model
3
+
4
+ class AllocationSet
5
+
6
+ # An array of variables
7
+ attr_accessor :variables
8
+
9
+ # An array of allocations for those variables.
10
+ # Each allocation is a an array like [0, 1] where indices match the variable array
11
+ # to represent values for that variable
12
+ attr_accessor :allocations
13
+
14
+ def initialize(variables, allocations)
15
+ if !allocations.empty? && variables.length != allocations.first.length
16
+ raise "Variables and allocations must match in length!"
17
+ end
18
+ @variables, @allocations = variables, allocations
19
+ end
20
+
21
+ def length()
22
+ allocations.length
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,34 @@
1
+
2
+ module PgVerify
3
+ module Model
4
+
5
+ class Assignment
6
+
7
+ ASSIGN_OPERATOR = ':='
8
+
9
+ # The name of the variable which is assigned a value
10
+ attr_accessor :assigned_variable
11
+
12
+ # The Model::Expression which of this assignment
13
+ attr_accessor :expression
14
+
15
+ def self.from_string(string)
16
+ raise "Not an assignment: #{string}" unless string.include?(ASSIGN_OPERATOR)
17
+ split = string.split(ASSIGN_OPERATOR).map(&:strip)
18
+ assigned_variable = split[0].to_sym
19
+ expression = Expression.from_string(split[1])
20
+ return Assignment.new(assigned_variable, expression)
21
+ end
22
+
23
+ def initialize(assigned_variable, expression)
24
+ @assigned_variable, @expression = assigned_variable, expression
25
+ end
26
+
27
+ def to_s()
28
+ return "#{assigned_variable} #{ASSIGN_OPERATOR} #{expression.to_s}"
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,40 @@
1
+
2
+ module PgVerify
3
+ module Model
4
+
5
+ class Component
6
+
7
+ # The name of this component as a symbol
8
+ attr_accessor :name
9
+ # A list of symbols representing states
10
+ attr_accessor :states
11
+ # A list of transitions between states
12
+ attr_accessor :transitions
13
+ # Flag on whether this component is used to represent a fault.
14
+ attr_accessor :represents_fault
15
+ # The source location of this components definition
16
+ attr_accessor :source_location
17
+
18
+ # A Model::ParsedExpression used as the init expression.
19
+ # This expression must hold true initially. It can be used
20
+ # to restrict or set the initial state and variables.
21
+ # Can be left as nil in order to not restrict anything
22
+ attr_accessor :init_expression
23
+
24
+ def initialize(args = {})
25
+ @name = ( args[:name] || raise('Blubb') )
26
+ @states = ( args[:states] || [] )
27
+ @transitions = ( args[:transitions] || [] )
28
+ @represents_fault = args[:represents_fault].nil? ? false : args[:represents_fault]
29
+ @source_location = ( args[:source_location] )
30
+ @init_expression = args[:init_expression]
31
+ end
32
+
33
+ def represents_fault?()
34
+ return @represents_fault
35
+ end
36
+
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,16 @@
1
+ module PgVerify
2
+ module Model
3
+
4
+ class Hazard
5
+
6
+ attr_accessor :text
7
+ attr_accessor :expression
8
+
9
+ def initialize(text, expression)
10
+ @text, @expression = text, expression
11
+ end
12
+
13
+ end
14
+
15
+ end
16
+ end