atp 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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