pg-verify 0.1.0

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.
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