atp 0.1.0 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 31ba0f5ad78ad309c007c6051c63abc61869d515
4
- data.tar.gz: 1506ab571ab5b6e8fe5c992bb95e81a7d866c8a7
3
+ metadata.gz: 7ca6eaefd174b135c5b39a8b2d287f24cd890814
4
+ data.tar.gz: 3c379de6d014a88c5dbec902ec85eda2d4d1abd6
5
5
  SHA512:
6
- metadata.gz: 457369eaa2650117fd6477073cf192368c7041782001852498119363e5940cd4048923b93194d072400dc4430f4f05eb5b67f40da5115994c7e57e495c971a5b
7
- data.tar.gz: 28f04f8b24bb72b32b0816d97833dfeb70809562967f7b13f1cfb096c0e9dd0b2affa38f7f0e4ad43f64a4a95c66ccfa8c1c363fbff0eb2560ff68c1d139c19d
6
+ metadata.gz: ec297a8c950f05a49eaa17c359d5c35378aea3e9a1e39f88f3c72906968658dc22e61590357f83b462f25dab699a1577d7d334efdb26d126b0f3694a159eaa9f
7
+ data.tar.gz: 1fc8899484368c2fc172801ba5bae1968fd9488d52420d0f0c30e1275a9db41783ab2886536317ca5744e2b7222badee59a9e6d5006d373b827f6e90d3bb6d80
File without changes
data/config/commands.rb CHANGED
@@ -29,13 +29,13 @@ when "my_command"
29
29
  # control flowing back to Origen
30
30
  exit 0
31
31
 
32
- ## Example of how to make a command to run unit tests, this simply invokes RSpec on
33
- ## the spec directory
34
- #when "specs"
35
- # ARGV.unshift "spec"
36
- # require "rspec"
37
- # require "rspec/autorun"
38
- # exit 0 # This will never be hit on a fail, RSpec will automatically exit 1
32
+ # Example of how to make a command to run unit tests, this simply invokes RSpec on
33
+ # the spec directory
34
+ when "specs"
35
+ ARGV.unshift "spec"
36
+ require "rspec"
37
+ require "rspec/autorun"
38
+ exit 0 # This will never be hit on a fail, RSpec will automatically exit 1
39
39
 
40
40
  ## Example of how to make a command to run diff-based tests
41
41
  #when "examples"
@@ -68,9 +68,9 @@ else
68
68
  # You probably want to also add the your commands to the help shown via
69
69
  # origen -h, you can do this be assigning the required text to @application_commands
70
70
  # before handing control back to Origen. Un-comment the example below to get started.
71
- # @application_commands = <<-EOT
72
- # specs Run the specs (tests), -c will enable coverage
71
+ @application_commands = <<-EOT
72
+ specs Run the specs (tests), -c will enable coverage
73
+ EOT
73
74
  # examples Run the examples (tests), -c will enable coverage
74
- # EOT
75
75
 
76
76
  end
data/config/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module ATP
2
2
  MAJOR = 0
3
- MINOR = 1
3
+ MINOR = 2
4
4
  BUGFIX = 0
5
5
  DEV = nil
6
6
 
data/lib/atp.rb CHANGED
@@ -1,15 +1,59 @@
1
1
  require 'origen'
2
- require_relative '../config/application.rb'
2
+ require_relative '../config/application.rb'
3
3
  module ATP
4
+ autoload :Program, 'atp/program'
5
+ autoload :Flow, 'atp/flow'
6
+ autoload :Processor, 'atp/processor'
7
+ autoload :Runner, 'atp/runner'
8
+ autoload :Formatter, 'atp/formatter'
9
+ autoload :Parser, 'atp/parser'
10
+ autoload :AND, 'atp/and'
11
+ autoload :OR, 'atp/or'
12
+ autoload :NOT, 'atp/not'
4
13
 
5
- # Load all files in the lib directory via a wildcard, if your project becomes
6
- # large or load order dependencies start to creep in then you may need to
7
- # start taking control of this manually as described above.
8
- # Note that there is no problem from requiring a file twice (Ruby will ignore
9
- # the second require), so if you have a file that must be required up front
10
- # you can do that one manually and the let the wildcard take care of the rest.
11
- Dir.glob("#{File.dirname(__FILE__)}/**/*.rb").sort.each do |file|
12
- require file
14
+ module AST
15
+ autoload :Node, 'atp/ast/node'
16
+ autoload :Builder, 'atp/ast/builder'
17
+ autoload :Factories, 'atp/ast/factories'
18
+ autoload :Extractor, 'atp/ast/extractor'
13
19
  end
14
20
 
21
+ # Processors actually modify the AST to clean and optimize the user input
22
+ # and to implement the flow control API
23
+ module Processors
24
+ autoload :Condition, 'atp/processors/condition'
25
+ autoload :Relationship, 'atp/processors/relationship'
26
+ autoload :PreCleaner, 'atp/processors/pre_cleaner'
27
+ autoload :PostCleaner, 'atp/processors/post_cleaner'
28
+ end
29
+
30
+ # Summarizers extract summary data from the given AST
31
+ module Summarizers
32
+ end
33
+
34
+ # Validators are run on the processed AST to check it for common errors or
35
+ # logical issues that will prevent it being rendered to a test program format
36
+ module Validators
37
+ autoload :Condition, 'atp/validators/condition'
38
+ end
39
+
40
+ # Formatters are run on the processed AST to display the flow or to render
41
+ # it to a different format
42
+ module Formatters
43
+ autoload :Basic, 'atp/formatters/basic'
44
+ autoload :Datalog, 'atp/formatters/datalog'
45
+ autoload :Graph, 'atp/formatters/graph'
46
+ end
47
+
48
+ def self.or(*args)
49
+ OR.new(*args)
50
+ end
51
+
52
+ def self.and(*args)
53
+ AND.new(*args)
54
+ end
55
+
56
+ def self.not(*args)
57
+ NOT.new(*args)
58
+ end
15
59
  end
data/lib/atp/and.rb ADDED
@@ -0,0 +1,11 @@
1
+ module ATP
2
+ class AND < ::Array
3
+ def initialize(*vals)
4
+ vals.flatten.each { |v| self << v }
5
+ end
6
+
7
+ def inspect
8
+ "AND#{super}"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,214 @@
1
+ module ATP
2
+ module AST
3
+ class Builder
4
+ include Factories
5
+
6
+ attr_reader :context
7
+
8
+ def flow
9
+ n0(:flow)
10
+ end
11
+
12
+ def name(str)
13
+ n(:name, str.to_s)
14
+ end
15
+
16
+ def log(str)
17
+ n(:log, str.to_s)
18
+ end
19
+
20
+ def render(str)
21
+ n(:render, str.to_s)
22
+ end
23
+
24
+ def description(str)
25
+ n(:description, str.to_s)
26
+ end
27
+
28
+ def id(symbol)
29
+ n(:id, symbol.to_sym)
30
+ end
31
+
32
+ def flow_flag(name, enabled, node)
33
+ n(:flow_flag, name, enabled, node)
34
+ end
35
+
36
+ def test_result(id, passed, node)
37
+ n(:test_result, id, passed, node)
38
+ end
39
+
40
+ def test_executed(id, executed, node)
41
+ n(:test_executed, id, executed, node)
42
+ end
43
+
44
+ def group(group_name, nodes, options = {})
45
+ children = [name(group_name)]
46
+
47
+ children << id(options[:id].to_s.downcase.to_sym) if options[:id]
48
+
49
+ children << on_fail(options[:on_fail]) if options[:on_fail]
50
+ children << on_pass(options[:on_pass]) if options[:on_pass]
51
+
52
+ children << n(:members, *nodes)
53
+ group = n(:group, *children)
54
+
55
+ if options[:conditions]
56
+ apply_conditions(group, options[:conditions])
57
+ else
58
+ group
59
+ end
60
+ end
61
+
62
+ def cz(setup, node)
63
+ n(:cz, setup, node)
64
+ end
65
+
66
+ def new_context
67
+ @context = { conditions: {} }
68
+ yield if block_given?
69
+ @context
70
+ end
71
+
72
+ CONDITION_KEYS = [
73
+ :if_enabled, :enabled, :enable_flag, :enable, :if_enable,
74
+ :unless_enabled, :not_enabled, :disabled, :disable, :unless_enable,
75
+ :if_failed, :unless_passed, :failed,
76
+ :if_passed, :unless_failed, :passed,
77
+ :if_ran, :if_executed,
78
+ :unless_ran, :unless_executed,
79
+ :job, :jobs, :if_job, :if_jobs,
80
+ :unless_job, :unless_jobs,
81
+ :if_any_failed, :unless_all_passed,
82
+ :if_all_failed, :unless_any_passed,
83
+ :if_any_passed, :unless_all_failed,
84
+ :if_all_passed, :unless_any_failed
85
+ ]
86
+
87
+ def apply_conditions(node, conditions)
88
+ conditions.each do |key, value|
89
+ key = key.to_s.downcase.to_sym
90
+ context[:conditions][key] = value
91
+ case key
92
+ when :if_enabled, :enabled, :enable_flag, :enable, :if_enable
93
+ node = flow_flag(value, true, node)
94
+ when :unless_enabled, :not_enabled, :disabled, :disable, :unless_enable
95
+ node = flow_flag(value, false, node)
96
+ when :if_failed, :unless_passed, :failed
97
+ if value.is_a?(Array)
98
+ fail 'if_failed only accepts one ID, use if_any_failed or if_all_failed for multiple IDs'
99
+ end
100
+ node = test_result(value, false, node)
101
+ when :if_passed, :unless_failed, :passed
102
+ if value.is_a?(Array)
103
+ fail 'if_passed only accepts one ID, use if_any_passed or if_all_passed for multiple IDs'
104
+ end
105
+ node = test_result(value, true, node)
106
+ when :if_any_failed, :unless_all_passed
107
+ node = test_result(value, false, node)
108
+ when :if_all_failed, :unless_any_passed
109
+ node = value.reduce(nil) do |nodes, val|
110
+ test_result(val, false, nodes ? nodes : node)
111
+ end
112
+ when :if_any_passed, :unless_all_failed
113
+ node = test_result(value, true, node)
114
+ when :if_all_passed, :unless_any_failed
115
+ node = value.reduce(nil) do |nodes, val|
116
+ test_result(val, true, nodes ? nodes : node)
117
+ end
118
+ when :if_ran, :if_executed
119
+ node = test_executed(value, true, node)
120
+ when :unless_ran, :unless_executed
121
+ node = test_executed(value, false, node)
122
+ when :job, :jobs, :if_job, :if_jobs
123
+ # Make sure these are wrapped by an OR, AND jobs doesn't make sense anyway
124
+ unless value.is_a?(OR)
125
+ value = ATP.or(value)
126
+ end
127
+ node = n(:job, apply_boolean(value), node)
128
+ when :unless_job, :unless_jobs
129
+ # Make sure these are wrapped by an OR, AND jobs doesn't make sense anyway
130
+ unless value.is_a?(OR)
131
+ value = ATP.or(value)
132
+ end
133
+ node = n(:job, apply_boolean(ATP.not(value)), node)
134
+ else
135
+ fail "Unknown test condition attribute - #{key} (#{value})"
136
+ end
137
+ end
138
+ node
139
+ end
140
+
141
+ def apply_boolean(value)
142
+ if value.is_a?(OR)
143
+ n(:or, *value.map { |v| apply_boolean(v) })
144
+ elsif value.is_a?(AND)
145
+ n(:and, *value.map { |v| apply_boolean(v) })
146
+ elsif value.is_a?(NOT)
147
+ n(:not, apply_boolean(value.value))
148
+ else
149
+ value
150
+ end
151
+ end
152
+
153
+ def test(object, options = {})
154
+ children = [n(:object, object)]
155
+
156
+ if n = (options[:name] || options[:tname] || options[:test_name])
157
+ children << name(n)
158
+ end
159
+ if n = (options[:number] || options[:num] || options[:tnum] || options[:test_number])
160
+ children << number(n)
161
+ end
162
+ d = options[:description] || options[:desc]
163
+ children << description(d) if d
164
+ children << id(options[:id].to_s.downcase.to_sym) if options[:id]
165
+
166
+ children << on_fail(options[:on_fail]) if options[:on_fail]
167
+ children << on_pass(options[:on_pass]) if options[:on_pass]
168
+
169
+ test = n(:test, *children)
170
+
171
+ if options[:conditions]
172
+ apply_conditions(test, options[:conditions])
173
+ else
174
+ test
175
+ end
176
+ end
177
+
178
+ def on_fail(options = {})
179
+ children = []
180
+ if options[:bin] || options[:softbin]
181
+ children << set_result(:fail, bin: options[:bin], softbin: options[:softbin], description: options[:bin_description])
182
+ end
183
+ children << continue if options[:continue]
184
+ n(:on_fail, *children)
185
+ end
186
+
187
+ def on_pass(options = {})
188
+ children = []
189
+ if options[:bin] || options[:softbin]
190
+ children << set_result(:pass, bin: options[:bin], softbin: options[:softbin], description: options[:bin_description])
191
+ end
192
+ children << continue if options[:continue]
193
+ n(:on_pass, *children)
194
+ end
195
+
196
+ def set_result(type, options = {})
197
+ children = []
198
+ children << type
199
+ children << n(:bin, options[:bin]) if options[:bin]
200
+ children << n(:softbin, options[:softbin]) if options[:softbin]
201
+ children << n(:description, options[:description]) if options[:description]
202
+ n(:set_result, *children)
203
+ end
204
+
205
+ def number(val)
206
+ n(:number, val.to_i)
207
+ end
208
+
209
+ def continue
210
+ n0(:continue)
211
+ end
212
+ end
213
+ end
214
+ end
@@ -0,0 +1,26 @@
1
+ require 'ast'
2
+ module ATP
3
+ module AST
4
+ class Extractor
5
+ include ::AST::Processor::Mixin
6
+
7
+ attr_reader :types
8
+ attr_reader :results
9
+
10
+ def process(node, types = nil)
11
+ if types
12
+ @types = types
13
+ @results = []
14
+ # node = AST::Node.new(:wrapper, node) unless node.respond_to?(:to_ast)
15
+ end
16
+ super(node) if node.respond_to?(:to_ast)
17
+ results
18
+ end
19
+
20
+ def handler_missing(node)
21
+ @results << node if types.include?(node.type)
22
+ process_all(node.children)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,13 @@
1
+ module ATP
2
+ module AST
3
+ module Factories
4
+ def n(type, *children)
5
+ ATP::AST::Node.new(type, children)
6
+ end
7
+
8
+ def n0(type)
9
+ ATP::AST::Node.new(type, [])
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,71 @@
1
+ require 'ast'
2
+ module ATP
3
+ module AST
4
+ class Node < ::AST::Node
5
+ include Factories
6
+
7
+ def initialize(type, children = [], properties = {})
8
+ # Always use strings instead of symbols in the AST, makes serializing
9
+ # back and forward to a string easier
10
+ children = children.map { |c| c.is_a?(Symbol) ? c.to_s : c }
11
+ super type, children, properties
12
+ end
13
+
14
+ # Create a new node from the given S-expression (a string)
15
+ def self.from_sexp(sexp)
16
+ @parser ||= Parser.new
17
+ @parser.string_to_ast(sexp)
18
+ end
19
+
20
+ # Adds an empty node of the given type to the children unless another
21
+ # node of the same type is already present
22
+ def ensure_node_present(type)
23
+ if children.any? { |n| n.type == type }
24
+ self
25
+ else
26
+ updated(nil, children + [n0(type)])
27
+ end
28
+ end
29
+
30
+ # Returns the value at the root of an AST node like this:
31
+ #
32
+ # node # => (module-def
33
+ # (module-name
34
+ # (SCALAR-ID "Instrument"))
35
+ #
36
+ # node.value # => "Instrument"
37
+ #
38
+ # No error checking is done and the caller is responsible for calling
39
+ # this only on compatible nodes
40
+ def value
41
+ val = children.first
42
+ val = val.children.first while val.respond_to?(:children)
43
+ val
44
+ end
45
+
46
+ # Add the given nodes to the children
47
+ def add(*nodes)
48
+ updated(nil, children + nodes)
49
+ end
50
+
51
+ # Returns the first child node of the given type that is found
52
+ def find(type)
53
+ nodes = find_all(type)
54
+ nodes.first
55
+ end
56
+
57
+ # Returns an array containing all child nodes of the given type(s)
58
+ def find_all(*types)
59
+ Extractor.new.process(self, types)
60
+ end
61
+
62
+ def to_h
63
+ h = {}
64
+ children.each do |node|
65
+ h[node.type] = node.children.map { |n| n.is_a?(AST::Node) ? n.to_h : n }
66
+ end
67
+ h
68
+ end
69
+ end
70
+ end
71
+ end