choria-mcorpc-support 2.23.0 → 2.24.1
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 +5 -5
- data/lib/mcollective.rb +3 -3
- data/lib/mcollective/agent/bolt_tasks.ddl +18 -0
- data/lib/mcollective/agent/bolt_tasks.json +18 -0
- data/lib/mcollective/agent/bolt_tasks.rb +4 -2
- data/lib/mcollective/agent/rpcutil.ddl +2 -2
- data/lib/mcollective/agent/rpcutil.json +2 -2
- data/lib/mcollective/application/choria.rb +3 -63
- data/lib/mcollective/application/facts.rb +2 -67
- data/lib/mcollective/application/federation.rb +1 -3
- data/lib/mcollective/application/find.rb +1 -1
- data/lib/mcollective/application/ping.rb +31 -3
- data/lib/mcollective/application/plugin.rb +2 -15
- data/lib/mcollective/application/tasks.rb +9 -0
- data/lib/mcollective/client.rb +1 -1
- data/lib/mcollective/config.rb +135 -103
- data/lib/mcollective/ddl.rb +0 -1
- data/lib/mcollective/discovery.rb +12 -65
- data/lib/mcollective/discovery/broadcast.ddl +11 -0
- data/lib/mcollective/discovery/choria.ddl +6 -4
- data/lib/mcollective/discovery/delegate.ddl +13 -0
- data/lib/mcollective/discovery/delegate.rb +73 -0
- data/lib/mcollective/discovery/external.ddl +13 -0
- data/lib/mcollective/discovery/file.ddl +13 -0
- data/lib/mcollective/discovery/flatfile.ddl +7 -5
- data/lib/mcollective/discovery/inventory.ddl +13 -0
- data/lib/mcollective/discovery/mc.ddl +3 -3
- data/lib/mcollective/generators.rb +0 -1
- data/lib/mcollective/message.rb +0 -24
- data/lib/mcollective/optionparser.rb +2 -2
- data/lib/mcollective/pluginpackager/forge_packager.rb +1 -1
- data/lib/mcollective/rpc/client.rb +6 -4
- data/lib/mcollective/security/base.rb +1 -37
- data/lib/mcollective/util.rb +23 -31
- data/lib/mcollective/util/choria.rb +0 -157
- data/lib/mcollective/util/tasks_support.rb +22 -3
- metadata +9 -27
- data/lib/mcollective/application/describe_filter.rb +0 -87
- data/lib/mcollective/data.rb +0 -96
- data/lib/mcollective/data/agent_data.ddl +0 -22
- data/lib/mcollective/data/agent_data.rb +0 -17
- data/lib/mcollective/data/base.rb +0 -68
- data/lib/mcollective/data/bolt_task_data.ddl +0 -90
- data/lib/mcollective/data/bolt_task_data.rb +0 -32
- data/lib/mcollective/data/collective_data.ddl +0 -20
- data/lib/mcollective/data/collective_data.rb +0 -9
- data/lib/mcollective/data/fact_data.ddl +0 -28
- data/lib/mcollective/data/fact_data.rb +0 -55
- data/lib/mcollective/data/fstat_data.ddl +0 -89
- data/lib/mcollective/data/fstat_data.rb +0 -54
- data/lib/mcollective/data/result.rb +0 -50
- data/lib/mcollective/ddl/dataddl.rb +0 -56
- data/lib/mcollective/discovery/choria.rb +0 -223
- data/lib/mcollective/discovery/flatfile.rb +0 -47
- data/lib/mcollective/discovery/stdin.ddl +0 -11
- data/lib/mcollective/discovery/stdin.rb +0 -67
- data/lib/mcollective/generators/data_generator.rb +0 -50
- data/lib/mcollective/generators/templates/data_input_snippet.erb +0 -7
- data/lib/mcollective/matcher.rb +0 -220
- data/lib/mcollective/matcher/parser.rb +0 -118
- data/lib/mcollective/matcher/scanner.rb +0 -236
@@ -1,47 +0,0 @@
|
|
1
|
-
# discovers against a flatfile instead of the traditional network discovery
|
2
|
-
# the flat file must have a node name per line which should match identities
|
3
|
-
# as configured
|
4
|
-
module MCollective
|
5
|
-
class Discovery
|
6
|
-
class Flatfile
|
7
|
-
def self.discover(filter, timeout, limit=0, client=nil)
|
8
|
-
if client.options[:discovery_options].empty?
|
9
|
-
raise "The flatfile discovery method needs a path to a text file"
|
10
|
-
else
|
11
|
-
file = client.options[:discovery_options].first
|
12
|
-
end
|
13
|
-
|
14
|
-
raise "Cannot read the file %s specified as discovery source" % file unless File.readable?(file)
|
15
|
-
|
16
|
-
discovered = []
|
17
|
-
hosts = []
|
18
|
-
|
19
|
-
File.readlines(file).each do |host|
|
20
|
-
host = host.chomp.strip
|
21
|
-
next if host.empty? || host.match(/^#/)
|
22
|
-
raise 'Identities can only match /^[\w\.\-]+$/' unless host.match(/^[\w.\-]+$/)
|
23
|
-
|
24
|
-
hosts << host
|
25
|
-
end
|
26
|
-
|
27
|
-
# this plugin only supports identity filters, do regex matches etc against
|
28
|
-
# the list found in the flatfile
|
29
|
-
if !filter["identity"].empty?
|
30
|
-
filter["identity"].each do |identity|
|
31
|
-
identity = Regexp.new(identity.gsub("\/", "")) if identity.match("^/")
|
32
|
-
|
33
|
-
if identity.is_a?(Regexp)
|
34
|
-
discovered = hosts.grep(identity)
|
35
|
-
elsif hosts.include?(identity)
|
36
|
-
discovered << identity
|
37
|
-
end
|
38
|
-
end
|
39
|
-
else
|
40
|
-
discovered = hosts
|
41
|
-
end
|
42
|
-
|
43
|
-
discovered
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
@@ -1,11 +0,0 @@
|
|
1
|
-
metadata :name => "stdin",
|
2
|
-
:description => "STDIN based discovery for node identities",
|
3
|
-
:author => "Tomas Doran <bobtfish@bobtfish.net.net>",
|
4
|
-
:license => "ASL 2.0",
|
5
|
-
:version => "0.1",
|
6
|
-
:url => "https://docs.puppetlabs.com/mcollective/",
|
7
|
-
:timeout => 0
|
8
|
-
|
9
|
-
discovery do
|
10
|
-
capabilities :identity
|
11
|
-
end
|
@@ -1,67 +0,0 @@
|
|
1
|
-
# discovers against stdin instead of the traditional network discovery
|
2
|
-
# the input must be a flat file with a node name per line which should match identities as configured,
|
3
|
-
# or it should be a json string as output by the -j option of mco rpc
|
4
|
-
require "mcollective/rpc/helpers"
|
5
|
-
|
6
|
-
module MCollective
|
7
|
-
class Discovery
|
8
|
-
class Stdin
|
9
|
-
def self.discover(filter, timeout, limit=0, client=nil)
|
10
|
-
if client.options[:discovery_options].empty?
|
11
|
-
type = "auto"
|
12
|
-
else
|
13
|
-
type = client.options[:discovery_options].first.downcase
|
14
|
-
end
|
15
|
-
|
16
|
-
discovered = []
|
17
|
-
|
18
|
-
file = $stdin.read
|
19
|
-
|
20
|
-
raise("data piped on STDIN contained only whitespace - could not discover hosts from it.") if file =~ /^\s*$/
|
21
|
-
|
22
|
-
if type == "auto"
|
23
|
-
if file =~ /^\s*\[/
|
24
|
-
type = "json"
|
25
|
-
else
|
26
|
-
type = "text"
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
Log.debug("Parsing STDIN input as type %s" % type)
|
31
|
-
|
32
|
-
case type
|
33
|
-
when "json"
|
34
|
-
hosts = RPC::Helpers.extract_hosts_from_json(file)
|
35
|
-
when "text"
|
36
|
-
hosts = file.split("\n")
|
37
|
-
else
|
38
|
-
raise("stdin discovery plugin only knows the types auto/text/json, not \"#{type}\"")
|
39
|
-
end
|
40
|
-
|
41
|
-
hosts.map do |host|
|
42
|
-
raise 'Identities can only match /\w\.\-/' unless host.match(/^[\w.\-]+$/)
|
43
|
-
|
44
|
-
host
|
45
|
-
end
|
46
|
-
|
47
|
-
# this plugin only supports identity filters, do regex matches etc against
|
48
|
-
# the list found in the flatfile
|
49
|
-
if filter["identity"].empty?
|
50
|
-
discovered = hosts
|
51
|
-
else
|
52
|
-
filter["identity"].each do |identity|
|
53
|
-
identity = Regexp.new(identity.gsub("\/", "")) if identity.match("^/")
|
54
|
-
|
55
|
-
if identity.is_a?(Regexp)
|
56
|
-
discovered = hosts.grep(identity)
|
57
|
-
elsif hosts.include?(identity)
|
58
|
-
discovered << identity
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
discovered
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
@@ -1,50 +0,0 @@
|
|
1
|
-
module MCollective
|
2
|
-
module Generators
|
3
|
-
class DataGenerator < Base
|
4
|
-
attr_accessor :ddl, :content
|
5
|
-
|
6
|
-
def initialize(plugin_name, outputs=[], name=nil, description=nil, author=nil,
|
7
|
-
license=nil, version=nil, url=nil, timeout=nil)
|
8
|
-
|
9
|
-
super(name, description, author, license, version, url, timeout)
|
10
|
-
@mod_name = "Data"
|
11
|
-
@pclass = "Base"
|
12
|
-
@plugin_name = plugin_name
|
13
|
-
@outputs = outputs
|
14
|
-
@ddl = create_ddl
|
15
|
-
@content = create_plugin_content
|
16
|
-
@plugin = create_plugin_string
|
17
|
-
write_plugins
|
18
|
-
end
|
19
|
-
|
20
|
-
def create_ddl
|
21
|
-
query_text = "dataquery :description => \"Query information\" do\n"
|
22
|
-
query_text += ERB.new(File.read(File.join(File.dirname(__FILE__), "templates", "data_input_snippet.erb"))).result
|
23
|
-
|
24
|
-
@outputs.each_with_index do |output, i|
|
25
|
-
query_text += "%2s%s" % [" ", "output :#{output},\n"]
|
26
|
-
query_text += "%9s%s" % [" ", ":description => \"%DESCRIPTION%\",\n"]
|
27
|
-
query_text += "%9s%s" % [" ", ":display_as => \"%DESCRIPTION%\"\n"]
|
28
|
-
query_text += "\n" unless @outputs.size == (i + 1)
|
29
|
-
end
|
30
|
-
|
31
|
-
query_text += "end"
|
32
|
-
|
33
|
-
# Use inherited method to create metadata part of the ddl
|
34
|
-
create_metadata_string + query_text
|
35
|
-
end
|
36
|
-
|
37
|
-
def create_plugin_content
|
38
|
-
content_text = "%6s%s" % [" ", "query do |what|\n"]
|
39
|
-
|
40
|
-
@outputs.each do |output|
|
41
|
-
content_text += "%8s%s" % [" ", "result[:#{output}] = nil\n"]
|
42
|
-
end
|
43
|
-
content_text += "%6s%s" % [" ", "end\n"]
|
44
|
-
|
45
|
-
# Add actions to agent file
|
46
|
-
content_text
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
data/lib/mcollective/matcher.rb
DELETED
@@ -1,220 +0,0 @@
|
|
1
|
-
module MCollective
|
2
|
-
# A parser and scanner that creates a stack machine for a simple
|
3
|
-
# fact and class matching language used on the CLI to facilitate
|
4
|
-
# a rich discovery language
|
5
|
-
#
|
6
|
-
# Language EBNF
|
7
|
-
#
|
8
|
-
# compound = ["("] expression [")"] {["("] expression [")"]}
|
9
|
-
# expression = [!|not]statement ["and"|"or"] [!|not] statement
|
10
|
-
# char = A-Z | a-z | < | > | => | =< | _ | - |* | / { A-Z | a-z | < | > | => | =< | _ | - | * | / | }
|
11
|
-
# int = 0|1|2|3|4|5|6|7|8|9{|0|1|2|3|4|5|6|7|8|9|0}
|
12
|
-
module Matcher
|
13
|
-
require "mcollective/matcher/parser"
|
14
|
-
require "mcollective/matcher/scanner"
|
15
|
-
|
16
|
-
# Helper creates a hash from a function call string
|
17
|
-
def self.create_function_hash(function_call)
|
18
|
-
func_hash = {}
|
19
|
-
f = ""
|
20
|
-
func_parts = function_call.split(/(!=|>=|<=|<|>|=)/)
|
21
|
-
func_hash["r_compare"] = func_parts.pop
|
22
|
-
func_hash["operator"] = func_parts.pop
|
23
|
-
func = func_parts.join
|
24
|
-
|
25
|
-
# Deal with dots in function parameters and functions without dot values
|
26
|
-
if func =~ /^.+\(.*\)$/
|
27
|
-
f = func
|
28
|
-
else
|
29
|
-
func_parts = func.split(".")
|
30
|
-
func_hash["value"] = func_parts.pop
|
31
|
-
f = func_parts.join(".")
|
32
|
-
end
|
33
|
-
|
34
|
-
# Deal with regular expression matches
|
35
|
-
if func_hash["r_compare"] =~ /^\/.*\/$/
|
36
|
-
func_hash["operator"] = "=~" if func_hash["operator"] == "="
|
37
|
-
func_hash["operator"] = "!=~" if func_hash["operator"] == "!="
|
38
|
-
func_hash["r_compare"] = Regexp.new(func_hash["r_compare"].gsub(/^\/|\/$/, ""))
|
39
|
-
# Convert = operators to == so they can be propperly evaluated
|
40
|
-
elsif func_hash["operator"] == "="
|
41
|
-
func_hash["operator"] = "=="
|
42
|
-
end
|
43
|
-
|
44
|
-
# Grab function name and parameters from left compare string
|
45
|
-
func_hash["name"], func_hash["params"] = f.split("(")
|
46
|
-
if func_hash["params"] == ")"
|
47
|
-
func_hash["params"] = nil
|
48
|
-
else
|
49
|
-
|
50
|
-
# Walk the function parameters from the front and from the
|
51
|
-
# back removing the first and last instances of single of
|
52
|
-
# double qoutes. We do this to handle the case where params
|
53
|
-
# contain escaped qoutes.
|
54
|
-
func_hash["params"] = func_hash["params"].gsub(")", "")
|
55
|
-
func_quotes = func_hash["params"].split(/('|")/)
|
56
|
-
|
57
|
-
func_quotes.each_with_index do |item, i|
|
58
|
-
if item =~ /'|"/
|
59
|
-
func_quotes.delete_at(i)
|
60
|
-
break
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
func_quotes.reverse.each_with_index do |item, i|
|
65
|
-
if item =~ /'|"/
|
66
|
-
func_quotes.delete_at(func_quotes.size - i - 1)
|
67
|
-
break
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
func_hash["params"] = func_quotes.join
|
72
|
-
end
|
73
|
-
|
74
|
-
func_hash
|
75
|
-
end
|
76
|
-
|
77
|
-
# Returns the result of an executed function
|
78
|
-
def self.execute_function(function_hash)
|
79
|
-
# In the case where a data plugin isn't present there are two ways we can handle
|
80
|
-
# the raised exception. The function result can either be false or the entire
|
81
|
-
# expression can fail.
|
82
|
-
#
|
83
|
-
# In the case where we return the result as false it opens us op to unexpected
|
84
|
-
# negation behavior.
|
85
|
-
#
|
86
|
-
# !foo('bar').name = bar
|
87
|
-
#
|
88
|
-
# In this case the user would expect discovery to match on all machines where
|
89
|
-
# the name value of the foo function does not equal bar. If a non existent function
|
90
|
-
# returns false then it is posible to match machines where the name value of the
|
91
|
-
# foo function is bar.
|
92
|
-
#
|
93
|
-
# Instead we raise a DDLValidationError to prevent this unexpected behavior from
|
94
|
-
# happening.
|
95
|
-
|
96
|
-
result = Data.send(function_hash["name"], function_hash["params"])
|
97
|
-
|
98
|
-
if function_hash["value"]
|
99
|
-
begin
|
100
|
-
eval_result = result.send(function_hash["value"])
|
101
|
-
rescue
|
102
|
-
# If data field has not been set we set the comparison result to nil
|
103
|
-
eval_result = nil
|
104
|
-
end
|
105
|
-
eval_result
|
106
|
-
else
|
107
|
-
result
|
108
|
-
end
|
109
|
-
rescue NoMethodError
|
110
|
-
Log.debug("cannot execute discovery function '#{function_hash['name']}'. data plugin not found")
|
111
|
-
raise DDLValidationError
|
112
|
-
end
|
113
|
-
|
114
|
-
# Evaluates a compound statement
|
115
|
-
def self.eval_compound_statement(expression)
|
116
|
-
case expression.values.first
|
117
|
-
when /^\//
|
118
|
-
Util.has_cf_class?(expression.values.first)
|
119
|
-
when />=|<=|=|<|>/
|
120
|
-
optype = expression.values.first.match(/>=|<=|=|<|>/)
|
121
|
-
name, value = expression.values.first.split(optype[0])
|
122
|
-
if value.split("")[0] == "/"
|
123
|
-
optype = "=~"
|
124
|
-
else
|
125
|
-
optype[0] == "=" ? optype = "==" : optype = optype[0]
|
126
|
-
end
|
127
|
-
|
128
|
-
Util.has_fact?(name, value, optype).to_s
|
129
|
-
else
|
130
|
-
Util.has_cf_class?(expression.values.first)
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
# Returns the result of an evaluated compound statement that
|
135
|
-
# includes a function
|
136
|
-
def self.eval_compound_fstatement(function_hash) # rubocop:disable Metrics/MethodLength
|
137
|
-
l_compare = execute_function(function_hash)
|
138
|
-
r_compare = function_hash["r_compare"]
|
139
|
-
operator = function_hash["operator"]
|
140
|
-
|
141
|
-
# Break out early and return false if the function returns nil
|
142
|
-
return false if l_compare.nil?
|
143
|
-
|
144
|
-
# Prevent unwanted discovery by limiting comparison operators
|
145
|
-
# on Strings and Booleans
|
146
|
-
if (l_compare.is_a?(String) || l_compare.is_a?(TrueClass) || l_compare.is_a?(FalseClass)) && function_hash["operator"].match(/<|>/)
|
147
|
-
Log.debug("Cannot do > and < comparison on Booleans and Strings '#{l_compare} #{function_hash['operator']} #{function_hash['r_compare']}'")
|
148
|
-
return false
|
149
|
-
end
|
150
|
-
|
151
|
-
# Prevent backticks in function parameters
|
152
|
-
if function_hash["params"] =~ /`/
|
153
|
-
Log.debug("Cannot use backticks in function parameters")
|
154
|
-
return false
|
155
|
-
end
|
156
|
-
|
157
|
-
# Do a regex comparison if right compare string is a regex
|
158
|
-
if operator =~ /(=~|!=~)/
|
159
|
-
# Fail if left compare value isn't a string
|
160
|
-
if l_compare.is_a?(String)
|
161
|
-
result = l_compare.match(r_compare)
|
162
|
-
# Flip return value for != operator
|
163
|
-
if function_hash["operator"] == "!=~"
|
164
|
-
!result
|
165
|
-
else
|
166
|
-
!!result
|
167
|
-
end
|
168
|
-
else
|
169
|
-
Log.debug("Cannot do a regex check on a non string value.")
|
170
|
-
false
|
171
|
-
end
|
172
|
-
# Otherwise do a normal comparison while taking the type into account
|
173
|
-
else
|
174
|
-
if l_compare.is_a? String
|
175
|
-
r_compare = r_compare.to_s
|
176
|
-
elsif r_compare.is_a? String
|
177
|
-
case l_compare
|
178
|
-
when Numeric
|
179
|
-
r_compare = r_compare.strip
|
180
|
-
begin
|
181
|
-
r_compare = Integer(r_compare)
|
182
|
-
rescue ArgumentError # rubocop:disable Metrics/BlockNesting
|
183
|
-
begin
|
184
|
-
r_compare = Float(r_compare)
|
185
|
-
rescue ArgumentError # rubocop:disable Metrics/BlockNesting
|
186
|
-
raise(ArgumentError, "invalid numeric value: #{r_compare}")
|
187
|
-
end
|
188
|
-
end
|
189
|
-
when TrueClass, FalseClass
|
190
|
-
r_compare = r_compare.strip
|
191
|
-
if r_compare == true.to_s # rubocop:disable Metrics/BlockNesting
|
192
|
-
r_compare = true
|
193
|
-
elsif r_compare == false.to_s # rubocop:disable Metrics/BlockNesting
|
194
|
-
r_compare = false
|
195
|
-
else
|
196
|
-
raise(ArgumentError, "invalid boolean value: #{r_compare}")
|
197
|
-
end
|
198
|
-
end
|
199
|
-
end
|
200
|
-
operator = operator.strip
|
201
|
-
if operator =~ /(?:(!=|<=|>=|<|>)|==?)/
|
202
|
-
operator = $1 ? $1.to_sym : :==
|
203
|
-
else
|
204
|
-
raise(ArgumentError, "invalid operator: #{operator}")
|
205
|
-
end
|
206
|
-
l_compare.send(operator, r_compare)
|
207
|
-
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
|
-
# Creates a callstack to be evaluated from a compound evaluation string
|
212
|
-
def self.create_compound_callstack(call_string)
|
213
|
-
callstack = Matcher::Parser.new(call_string).execution_stack
|
214
|
-
callstack.each_with_index do |statement, i|
|
215
|
-
callstack[i]["fstatement"] = create_function_hash(statement.values.first) if statement.keys.first == "fstatement"
|
216
|
-
end
|
217
|
-
callstack
|
218
|
-
end
|
219
|
-
end
|
220
|
-
end
|
@@ -1,118 +0,0 @@
|
|
1
|
-
# rubocop:disable Metrics/BlockNesting
|
2
|
-
module MCollective
|
3
|
-
module Matcher
|
4
|
-
class Parser
|
5
|
-
attr_reader :scanner, :execution_stack
|
6
|
-
|
7
|
-
def initialize(args)
|
8
|
-
@scanner = Scanner.new(args)
|
9
|
-
@execution_stack = []
|
10
|
-
@parse_errors = []
|
11
|
-
@token_errors = []
|
12
|
-
@paren_errors = []
|
13
|
-
parse
|
14
|
-
exit_with_token_errors unless @token_errors.empty?
|
15
|
-
exit_with_parse_errors unless @parse_errors.empty?
|
16
|
-
exit_with_paren_errors unless @paren_errors.empty?
|
17
|
-
end
|
18
|
-
|
19
|
-
# Exit and highlight any malformed tokens
|
20
|
-
def exit_with_token_errors
|
21
|
-
@token_errors.each do |error_range|
|
22
|
-
(error_range[0]..error_range[1]).each do |i|
|
23
|
-
@scanner.arguments[i] = Util.colorize(:red, @scanner.arguments[i])
|
24
|
-
end
|
25
|
-
end
|
26
|
-
raise "Malformed token(s) found while parsing -S input #{@scanner.arguments.join}"
|
27
|
-
end
|
28
|
-
|
29
|
-
def exit_with_parse_errors
|
30
|
-
@parse_errors.each do |error_range|
|
31
|
-
(error_range[0]..error_range[1]).each do |i|
|
32
|
-
@scanner.arguments[i] = Util.colorize(:red, @scanner.arguments[i])
|
33
|
-
end
|
34
|
-
end
|
35
|
-
raise "Parse errors found while parsing -S input #{@scanner.arguments.join}"
|
36
|
-
end
|
37
|
-
|
38
|
-
def exit_with_paren_errors
|
39
|
-
@paren_errors.each do |i|
|
40
|
-
@scanner.arguments[i] = Util.colorize(:red, @scanner.arguments[i])
|
41
|
-
end
|
42
|
-
raise "Missing parenthesis found while parsing -S input #{@scanner.arguments.join}"
|
43
|
-
end
|
44
|
-
|
45
|
-
# Parse the input string, one token at a time a contruct the call stack
|
46
|
-
def parse # rubocop:disable Metrics/MethodLength
|
47
|
-
pre_index = @scanner.token_index
|
48
|
-
p_token = nil
|
49
|
-
c_token, c_token_value = @scanner.get_token
|
50
|
-
|
51
|
-
until c_token.nil?
|
52
|
-
@scanner.token_index += 1
|
53
|
-
n_token, n_token_value = @scanner.get_token
|
54
|
-
|
55
|
-
unless n_token == " "
|
56
|
-
case c_token
|
57
|
-
when "bad_token"
|
58
|
-
@token_errors << c_token_value
|
59
|
-
|
60
|
-
when "and"
|
61
|
-
unless (n_token =~ /not|fstatement|statement|\(/) || (scanner.token_index == scanner.arguments.size) && !n_token.nil?
|
62
|
-
@parse_errors << [pre_index, scanner.token_index]
|
63
|
-
end
|
64
|
-
|
65
|
-
case p_token
|
66
|
-
when nil
|
67
|
-
@parse_errors << [pre_index - c_token.size, scanner.token_index]
|
68
|
-
when "and", "or"
|
69
|
-
@parse_errors << [pre_index - 1 - p_token.size, pre_index - 1]
|
70
|
-
end
|
71
|
-
|
72
|
-
when "or"
|
73
|
-
unless (n_token =~ /not|fstatement|statement|\(/) || (scanner.token_index == scanner.arguments.size) && !n_token.nil?
|
74
|
-
@parse_errors << [pre_index, scanner.token_index]
|
75
|
-
end
|
76
|
-
|
77
|
-
case p_token
|
78
|
-
when nil
|
79
|
-
@parse_errors << [pre_index - c_token.size, scanner.token_index]
|
80
|
-
when "and", "or"
|
81
|
-
@parse_errors << [pre_index - 1 - p_token.size, pre_index - 1]
|
82
|
-
end
|
83
|
-
|
84
|
-
when "not"
|
85
|
-
@parse_errors << [pre_index, scanner.token_index] unless n_token =~ /fstatement|statement|\(|not/ && !n_token.nil?
|
86
|
-
|
87
|
-
when "statement", "fstatement"
|
88
|
-
@parse_errors << [pre_index, scanner.token_index] if n_token !~ /and|or|\)/ && scanner.token_index != scanner.arguments.size
|
89
|
-
|
90
|
-
when ")"
|
91
|
-
@parse_errors << [pre_index, scanner.token_index] if n_token !~ /|and|or|not|\(/ && scanner.token_index != scanner.arguments.size
|
92
|
-
if @paren_errors.empty?
|
93
|
-
@paren_errors.push(n_token.nil? ? scanner.token_index - 1 : scanner.token_index - n_token_value.size)
|
94
|
-
else
|
95
|
-
@paren_errors.pop
|
96
|
-
end
|
97
|
-
|
98
|
-
when "("
|
99
|
-
@parse_errors << [pre_index, scanner.token_index] unless n_token =~ /fstatement|statement|not|\(/
|
100
|
-
@paren_errors.push(n_token.nil? ? scanner.token_index - 1 : scanner.token_index - n_token_value.size)
|
101
|
-
|
102
|
-
else
|
103
|
-
@parse_errors << [pre_index, scanner.token_index]
|
104
|
-
end
|
105
|
-
|
106
|
-
@execution_stack << {c_token => c_token_value} unless n_token == " " || c_token == "bad_token"
|
107
|
-
|
108
|
-
p_token = c_token
|
109
|
-
c_token = n_token
|
110
|
-
c_token_value = n_token_value
|
111
|
-
end
|
112
|
-
pre_index = @scanner.token_index
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
# rubocop:enable Metrics/BlockNesting
|