@@ -166,6 +166,7 @@ function _fis(ex::Expr, type)
166
166
@capture ex function name_ (argsin__):: ({argsout__} | argsout__)
167
167
body_
168
168
end
169
+ argsin, argsout = process_args (argsin), process_args (argsout)
169
170
inputs, outputs, opts, rules = parse_body (body, argsin, argsout, type)
170
171
171
172
fis = :($ type (; name = $ (QuoteNode (name)), inputs = $ inputs,
@@ -174,6 +175,29 @@ function _fis(ex::Expr, type)
174
175
return fis
175
176
end
176
177
178
+ process_args (x:: Symbol ) = [x]
179
+ function process_args (ex:: Expr )
180
+ if @capture (ex, x_[start_: stop_])
181
+ [Symbol (x, i) for i in start: stop]
182
+ else
183
+ throw (ArgumentError (" invalid expression $ex " ))
184
+ end
185
+ end
186
+ process_args (v:: Vector ) = mapreduce (process_args, vcat, v)
187
+
188
+ """
189
+ convert a symbol or expression to variable name. A symbol is returned as such.
190
+ An expression in the form `:(x[i])` is converted to a symbol `:xi`.
191
+ """
192
+ to_var_name (ex:: Symbol ) = ex
193
+ function to_var_name (ex:: Expr )
194
+ if @capture (ex, x_[i_])
195
+ return Symbol (x, eval (i))
196
+ else
197
+ throw (ArgumentError (" Invalid variable name $ex " ))
198
+ end
199
+ end
200
+
177
201
function parse_variable (var, args)
178
202
mfs = :(dictionary ([]))
179
203
ex = :(Variable ())
@@ -197,32 +221,46 @@ function parse_body(body, argsin, argsout, type)
197
221
outputs = :(dictionary ([]))
198
222
for line in body. args
199
223
line isa LineNumberNode && continue
200
- if @capture (line, var_:= begin args__ end )
201
- if var in argsin
202
- push! (inputs. args[2 ]. args, parse_variable (var, args))
203
- elseif var in argsout
204
- # TODO : makes this more scalable
205
- push! (outputs. args[2 ]. args,
206
- type == :SugenoFuzzySystem ? parse_sugeno_output (var, args, argsin) :
207
- parse_variable (var, args))
208
- else
209
- throw (ArgumentError (" Undefined variable $var " ))
210
- end
211
- elseif @capture (line, var_= value_)
212
- var in SETTINGS[type] ||
213
- throw (ArgumentError (" Invalid keyword $var in line $line " ))
214
- push! (opts, Expr (:kw , var, value isa Symbol ? :($ value ()) : value))
215
- elseif @capture (line, ant_--> (cons__,) * w_Number)
216
- push! (rules. args, parse_rule (ant, cons, w))
217
- elseif @capture (line, ant_--> p_ == q_ * w_Number)
218
- push! (rules. args, parse_rule (ant, [:($ p == $ q)], w))
219
- elseif @capture (line, ant_--> (cons__,) | cons__)
220
- push! (rules. args, parse_rule (ant, cons))
224
+ parse_line! (inputs, outputs, rules, opts, line, argsin, argsout, type)
225
+ end
226
+ return inputs, outputs, opts, rules
227
+ end
228
+
229
+ function parse_line! (inputs, outputs, rules, opts, line, argsin, argsout, type)
230
+ if @capture (line, var_:= begin args__ end )
231
+ var = to_var_name (var)
232
+ if var in argsin
233
+ push! (inputs. args[2 ]. args, parse_variable (var, args))
234
+ elseif var in argsout
235
+ # TODO : makes this more scalable
236
+ push! (outputs. args[2 ]. args,
237
+ type == :SugenoFuzzySystem ? parse_sugeno_output (var, args, argsin) :
238
+ parse_variable (var, args))
221
239
else
222
- throw (ArgumentError (" Invalid expression $line " ))
240
+ throw (ArgumentError (" Undefined variable $var " ))
223
241
end
242
+ elseif @capture (line, for i_ in start_: stop_
243
+ sts__
244
+ end )
245
+ for j in start: stop
246
+ for st in sts
247
+ ex = MacroTools. postwalk (x -> x == i ? j : x, st)
248
+ parse_line! (inputs, outputs, rules, opts, ex, argsin, argsout, type)
249
+ end
250
+ end
251
+ elseif @capture (line, var_= value_)
252
+ var in SETTINGS[type] ||
253
+ throw (ArgumentError (" Invalid keyword $var in line $line " ))
254
+ push! (opts, Expr (:kw , var, value isa Symbol ? :($ value ()) : value))
255
+ elseif @capture (line, ant_--> (cons__,) * w_Number)
256
+ push! (rules. args, parse_rule (ant, cons, w))
257
+ elseif @capture (line, ant_--> p_ == q_ * w_Number)
258
+ push! (rules. args, parse_rule (ant, [:($ p == $ q)], w))
259
+ elseif @capture (line, ant_--> (cons__,) | cons__)
260
+ push! (rules. args, parse_rule (ant, cons))
261
+ else
262
+ throw (ArgumentError (" Invalid expression $line " ))
224
263
end
225
- return inputs, outputs, opts, rules
226
264
end
227
265
228
266
# ################
@@ -243,9 +281,11 @@ function parse_antecedent(ant)
243
281
elseif @capture (ant, left_|| right_)
244
282
return Expr (:call , :FuzzyOr , parse_antecedent (left), parse_antecedent (right))
245
283
elseif @capture (ant, subj_== prop_)
246
- return Expr (:call , :FuzzyRelation , QuoteNode (subj), QuoteNode (prop))
284
+ return Expr (:call , :FuzzyRelation , QuoteNode (to_var_name (subj)),
285
+ QuoteNode (to_var_name (prop)))
247
286
elseif @capture (ant, subj_!= prop_)
248
- return Expr (:call , :FuzzyNegation , QuoteNode (subj), QuoteNode (prop))
287
+ return Expr (:call , :FuzzyNegation , QuoteNode (to_var_name (subj)),
288
+ QuoteNode (to_var_name (prop)))
249
289
else
250
290
throw (ArgumentError (" Invalid premise $ant " ))
251
291
end
254
294
function parse_consequents (cons)
255
295
newcons = map (cons) do c
256
296
@capture (c, subj_== prop_) || throw (ArgumentError (" Invalid consequence $c " ))
257
- Expr (:call , :FuzzyRelation , QuoteNode (subj), QuoteNode (prop))
297
+ Expr (:call , :FuzzyRelation , QuoteNode (to_var_name (subj)),
298
+ QuoteNode (to_var_name (prop)))
258
299
end
259
300
return Expr (:vect , newcons... )
260
301
end
0 commit comments