Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 3.7% 6 / 0 / 164
Functions: -% 0 / 1 / 1
Branches: 3.8% 4 / 0 / 106

OMCompiler/Compiler/Script/RewriteRules.mo
Line Branch Exec Source
1 /*
2 * This file is part of OpenModelica.
3 *
4 * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC),
5 * c/o Linköpings universitet, Department of Computer and Information Science,
6 * SE-58183 Linköping, Sweden.
7 *
8 * All rights reserved.
9 *
10 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR
11 * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8.
12 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
13 * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL
14 * VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
15 *
16 * The OpenModelica software and the OSMC (Open Source Modelica Consortium)
17 * Public License (OSMC-PL) are obtained from OSMC, either from the above
18 * address, from the URLs:
19 * http://www.openmodelica.org or
20 * https://github.com/OpenModelica/ or
21 * http://www.ida.liu.se/projects/OpenModelica,
22 * and in the OpenModelica distribution.
23 *
24 * GNU AGPL version 3 is obtained from:
25 * https://www.gnu.org/licenses/licenses.html#GPL
26 *
27 * This program is distributed WITHOUT ANY WARRANTY; without
28 * even the implied warranty of MERCHANTABILITY or FITNESS
29 * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
30 * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
31 *
32 * See the full OSMC Public License conditions for more details.
33 *
34 */
35
36 encapsulated package RewriteRules
37 " file: RewriteRules.mo
38 package: RewriteRules
39 description: RewriteRules applies user given rewrite rules to the Absyn expressions
40
41
42 "
43
44 public import Absyn;
45 public import AbsynUtil;
46 public import DAE;
47 public import Global;
48
49 public uniontype Rule
50 "rule to rewrite fromExp -> toExp,
51 there are FrontEnd and BackEnd rules"
52
53 record FRONTEND_RULE "rule to rewrite fromExp -> toExp, apply to FrontEnd AST exps"
54 Absyn.Exp from;
55 Absyn.Exp to;
56 end FRONTEND_RULE;
57
58 record BACKEND_RULE "rule to rewrite fromExp -> toExp, apply to the BackEnd AST exps"
59 Absyn.Exp from;
60 Absyn.Exp to;
61 end BACKEND_RULE;
62
63 end Rule;
64
65 public type Rules = list<Rule>;
66
67 public uniontype Bind "a bind '$1' bound to an exp"
68
69 record FRONTEND_BIND "a bind '$1' bound to an exp (frontend) "
70 Absyn.Exp slot;
71 Absyn.Exp value;
72 end FRONTEND_BIND;
73
74 record BACKEND_BIND "a bind '$1' bound to an exp (backend) "
75 DAE.Exp slot;
76 DAE.Exp value;
77 end BACKEND_BIND;
78
79 end Bind;
80
81 public type Binds = list<Bind>;
82
83 protected import Dump;
84 protected import Error;
85 protected import Expression;
86 protected import ExpressionBasics;
87 protected import Flags;
88 protected import GlobalScript;
89 protected import GlobalScriptDump;
90 protected import List;
91 protected import Parser;
92 protected import System;
93
94 // frontend rewrite stuff
95 // ----------------------
96 public function rewriteFrontEnd
97 input Absyn.Exp inExp;
98 output Absyn.Exp outExp;
99 output Boolean isChanged;
100 algorithm
101 (outExp, isChanged) := match inExp
102 local
103 Rules rules;
104 Boolean b;
105
106 case _
107 algorithm
108 ✗ rules := getRulesFrontEnd(getAllRules());
109 ✗ (outExp, b) := matchAndRewriteExpFrontEnd(inExp, rules);
110 then
111 (outExp, b);
112
113 end match;
114 end rewriteFrontEnd;
115
116 public function matchAndRewriteExpFrontEnd
117 "tries to match each of the rewrite rule
118 to the input expression and bind the place
119 holders to actual expression"
120 input Absyn.Exp inExp;
121 input Rules inRules;
122 output Absyn.Exp outExp;
123 output Boolean changed;
124 algorithm
125 (outExp, changed) := matchcontinue inRules
126 local
127 Absyn.Exp from, to;
128 Rules rest;
129 Binds binds;
130 Boolean b;
131
132 // nothing matched!
133 ✗ case {} then (inExp, false);
134
135 // matches the head
136 case FRONTEND_RULE(from, to)::_
137 algorithm
138 ✗ binds as _::_ := matchesFrontEnd(inExp, from, {});
139 ✗ outExp := rewriteExpFrontEnd(to, binds);
140 ✗ b := boolNot(referenceEq(inExp, outExp));
141 ✗ print("FrontEnd Exp: " + Dump.printExpStr(inExp) + "\n" +
142 "FrontEnd From: " + Dump.printExpStr(from) + "\n" +
143 "FrontEnd To: " + Dump.printExpStr(to) + "\n" +
144 "FrontEnd Rewrite: " + Dump.printExpStr(outExp) + "\n---------\n");
145 ✗ then
146 (outExp, b);
147
148 // not match for the head, try next
149 case _::rest
150 algorithm
151 ✗ (outExp, b) := matchAndRewriteExpFrontEnd(inExp, rest);
152 then
153 (outExp, b);
154
155 end matchcontinue;
156 end matchAndRewriteExpFrontEnd;
157
158 public function rewriteExpFrontEnd
159 input Absyn.Exp inExp;
160 input Binds inBinds;
161 output Absyn.Exp outExp;
162 algorithm
163 ✗ (outExp, _) := AbsynUtil.traverseExp(inExp, replaceBindsFrontEnd, inBinds);
164 end rewriteExpFrontEnd;
165
166 public function replaceBindsFrontEnd
167 input Absyn.Exp inExp;
168 input Binds inBinds;
169 output Absyn.Exp outExp;
170 output Binds outBinds;
171 algorithm
172 (outExp,outBinds) := match (inExp,inBinds)
173 local
174 Absyn.Exp e1,e2;
175 Binds bnds;
176
177 case (e1 as Absyn.CREF(_), bnds)
178 algorithm
179 ✗ e2 := replaceBindFrontEnd(e1, bnds);
180 then
181 (e2, bnds);
182
183 // leave as it is
184 else (inExp,inBinds);
185
186 end match;
187 end replaceBindsFrontEnd;
188
189 public function replaceBindFrontEnd
190 input Absyn.Exp inExp;
191 input Binds inBinds;
192 output Absyn.Exp outExp;
193 protected
194 Absyn.Exp e;
195 algorithm
196 ✗ for bind in inBinds loop
197 ✗ FRONTEND_BIND(e, outExp) := bind;
198
199 ✗ if AbsynUtil.expEqual(inExp, e) then
200 ✗ return;
201 end if;
202 end for;
203
204 // Couldn't find matching binding, return inExp.
205 outExp := inExp;
206 end replaceBindFrontEnd;
207
208 public function matchesFrontEnd
209 "@author: adrpo
210 unifies two absyn expressions and if they match
211 binds the placeholders '$1', '$2' to actual
212 expressions from inExp.
213 returns a list of BIND('$1', exp1)
214 or fails if the expressions cannot be unified"
215 input Absyn.Exp inExp;
216 input Absyn.Exp inUnifyWith;
217 input Binds inAcc;
218 output Binds outBinds;
219 algorithm
220 outBinds := matchcontinue(inExp, inUnifyWith)
221 local
222 Absyn.Exp e1a, e2a, e1b, e2b, cond1a, cond1b;
223 Absyn.Operator op1a, op1b;
224 Absyn.ComponentRef cr1a, cr1b;
225 Absyn.FunctionArgs fargs1a, fargs1b;
226 list<Absyn.Exp> exps1a, exps1b;
227 list<list<Absyn.Exp>> expsLst1a, expsLst1b;
228 Option<Absyn.Exp> oe1a, oe1b;
229 Absyn.Ident id1a, id1b;
230
231 // we have a place holder
232 case (_, Absyn.CREF(_))
233 algorithm
234 ✗ true := isPlaceHolderFrontEnd(inUnifyWith);
235 ✗ outBinds := FRONTEND_BIND(inUnifyWith, inExp)::inAcc;
236 then
237 outBinds;
238
239 // must be equal
240 case (Absyn.INTEGER(_), _)
241 algorithm
242 ✗ true := AbsynUtil.expEqual(inExp, inUnifyWith);
243 then
244 inAcc;
245
246 case (Absyn.REAL(_), _)
247 algorithm
248 ✗ true := AbsynUtil.expEqual(inExp, inUnifyWith);
249 then
250 inAcc;
251
252 case (Absyn.STRING(_), _)
253 algorithm
254 ✗ true := AbsynUtil.expEqual(inExp, inUnifyWith);
255 then
256 inAcc;
257
258 case (Absyn.BOOL(_), _)
259 algorithm
260 ✗ true := AbsynUtil.expEqual(inExp, inUnifyWith);
261 then
262 inAcc;
263
264 // cref
265 case (Absyn.CREF(_), _)
266 algorithm
267 ✗ true := AbsynUtil.expEqual(inExp, inUnifyWith);
268 then
269 inAcc;
270
271 case (Absyn.BINARY(e1a, op1a, e2a), Absyn.BINARY(e1b, op1b, e2b))
272 algorithm
273 ✗ true := AbsynUtil.opEqual(op1a, op1b);
274 ✗ outBinds := matchesFrontEnd(e1a, e1b, inAcc);
275 ✗ outBinds := matchesFrontEnd(e2a, e2b, outBinds);
276 then
277 outBinds;
278
279 case (Absyn.UNARY(op1a, e1a), Absyn.UNARY(op1b, e1b))
280 algorithm
281 ✗ true := AbsynUtil.opEqual(op1a, op1b);
282 ✗ outBinds := matchesFrontEnd(e1a, e1b, inAcc);
283 then
284 outBinds;
285
286 case (Absyn.LBINARY(e1a, op1a, e2a), Absyn.LBINARY(e1b, op1b, e2b))
287 algorithm
288 ✗ true := AbsynUtil.opEqual(op1a, op1b);
289 ✗ outBinds := matchesFrontEnd(e1a, e1b, inAcc);
290 ✗ outBinds := matchesFrontEnd(e2a, e2b, outBinds);
291 then
292 outBinds;
293
294 case (Absyn.LUNARY(op1a, e1a), Absyn.LUNARY(op1b, e1b))
295 algorithm
296 ✗ true := AbsynUtil.opEqual(op1a, op1b);
297 ✗ outBinds := matchesFrontEnd(e1a, e1b, inAcc);
298 then
299 outBinds;
300
301 case (Absyn.RELATION(e1a, op1a, e2a), Absyn.RELATION(e1b, op1b, e2b))
302 algorithm
303 ✗ true := AbsynUtil.opEqual(op1a, op1b);
304 ✗ outBinds := matchesFrontEnd(e1a, e1b, inAcc);
305 ✗ outBinds := matchesFrontEnd(e2a, e2b, outBinds);
306 then
307 outBinds;
308
309 case (Absyn.IFEXP(cond1a, e1a, e2a, _), Absyn.IFEXP(cond1b, e1b, e2b, _))
310 algorithm
311 ✗ outBinds := matchesFrontEnd(cond1a, cond1b, inAcc);
312 ✗ outBinds := matchesFrontEnd(e1a, e1b, outBinds);
313 ✗ outBinds := matchesFrontEnd(e2a, e2b, outBinds);
314 // TODO! handle elseif
315 // outBinds = matchesElseIf(elseIfa, elseIfb, outBinds);
316 then
317 outBinds;
318
319 case (Absyn.CALL(cr1a, fargs1a), Absyn.CALL(cr1b, fargs1b))
320 algorithm
321 ✗ true := AbsynUtil.crefEqual(cr1a, cr1b);
322 ✗ outBinds := matchesFargsFrontEnd(fargs1a, fargs1b, inAcc);
323 then
324 outBinds;
325
326 case (Absyn.PARTEVALFUNCTION(cr1a, fargs1a), Absyn.PARTEVALFUNCTION(cr1b, fargs1b))
327 algorithm
328 ✗ true := AbsynUtil.crefEqual(cr1a, cr1b);
329 ✗ outBinds := matchesFargsFrontEnd(fargs1a, fargs1b, inAcc);
330 then
331 outBinds;
332
333 case (Absyn.ARRAY(exps1a), Absyn.ARRAY(exps1b))
334 algorithm
335 ✗ outBinds := matchesExpLstFrontEnd(exps1a, exps1b, inAcc);
336 then
337 outBinds;
338
339 case (Absyn.MATRIX(expsLst1a), Absyn.MATRIX(expsLst1b))
340 algorithm
341 ✗ outBinds := matchesExpLstLstFrontEnd(expsLst1a, expsLst1b, inAcc);
342 then
343 outBinds;
344
345 case (Absyn.RANGE(e1a, oe1a, e2a), Absyn.RANGE(e1b, oe1b, e2b))
346 algorithm
347 ✗ outBinds := matchesFrontEnd(e1a, e1b, inAcc);
348 ✗ outBinds := matchesExpOptFrontEnd(oe1a, oe1b, outBinds);
349 ✗ outBinds := matchesFrontEnd(e2a, e2b, outBinds);
350 then
351 outBinds;
352
353 case (Absyn.TUPLE(exps1a), Absyn.TUPLE(exps1b))
354 algorithm
355 ✗ outBinds := matchesExpLstFrontEnd(exps1a, exps1b, inAcc);
356 then
357 outBinds;
358
359 case (Absyn.END(), Absyn.END()) then inAcc;
360
361 case (Absyn.CODE(_), Absyn.CODE(_)) then inAcc;
362
363 case (Absyn.AS(id1a, e1a), Absyn.AS(id1b, e1b))
364 algorithm
365 ✗ true := stringEq(id1a, id1b);
366 ✗ outBinds := matchesFrontEnd(e1a, e1b, inAcc);
367 then outBinds;
368
369 case (Absyn.CONS(e1a, e2a), Absyn.CONS(e1b, e2b))
370 algorithm
371 ✗ outBinds := matchesFrontEnd(e1a, e1b, inAcc);
372 ✗ outBinds := matchesFrontEnd(e2a, e2b, outBinds);
373 then outBinds;
374
375 // TODO! support matchexp
376 case (Absyn.MATCHEXP(), Absyn.MATCHEXP())
377 then inAcc;
378
379 case (Absyn.LIST(exps1a), Absyn.LIST(exps1b))
380 algorithm
381 ✗ outBinds := matchesExpLstFrontEnd(exps1a, exps1b, inAcc);
382 then
383 outBinds;
384 end matchcontinue;
385 end matchesFrontEnd;
386
387 public function matchesExpOptFrontEnd
388 input Option<Absyn.Exp> inOExp1;
389 input Option<Absyn.Exp> inOExp2;
390 input Binds inAcc;
391 output Binds outBinds;
392 algorithm
393 outBinds := match(inOExp1, inOExp2)
394 local Absyn.Exp e1a, e1b;
395 case (NONE(), NONE()) then inAcc;
396 case (SOME(e1a), SOME(e1b))
397 algorithm
398 ✗ outBinds := matchesFrontEnd(e1a, e1b, inAcc);
399 then
400 outBinds;
401 else fail();
402 end match;
403 end matchesExpOptFrontEnd;
404
405 public function matchesExpLstFrontEnd
406 input list<Absyn.Exp> inExps1;
407 input list<Absyn.Exp> inExps2;
408 input Binds inAcc;
409 output Binds outBinds;
410 algorithm
411 outBinds := match(inExps1, inExps2)
412 local
413 Absyn.Exp e1a, e1b;
414 list<Absyn.Exp> exps1a, exps1b;
415
416 case ({}, {}) then inAcc;
417 case (e1a::exps1a, e1b::exps1b)
418 algorithm
419 ✗ outBinds := matchesFrontEnd(e1a, e1b, inAcc);
420 ✗ outBinds := matchesExpLstFrontEnd(exps1a, exps1b, outBinds);
421 then
422 outBinds;
423
424 end match;
425 end matchesExpLstFrontEnd;
426
427 public function matchesFargsFrontEnd
428 input Absyn.FunctionArgs inFargs1;
429 input Absyn.FunctionArgs inFargs2;
430 input Binds inAcc;
431 output Binds outBinds;
432 algorithm
433 outBinds := match(inFargs1, inFargs2)
434 local
435 list<Absyn.Exp> exps1a, exps1b;
436 list<Absyn.NamedArg> nargs1a, nargs1b;
437 Absyn.Exp e1a, e1b;
438
439 case (Absyn.FUNCTIONARGS(exps1a, nargs1a), Absyn.FUNCTIONARGS(exps1b, nargs1b))
440 algorithm
441 ✗ outBinds := matchesExpLstFrontEnd(exps1a, exps1b, inAcc);
442 // fargs should be equal
443 ✗ true := intEq(listLength(nargs1a), listLength(nargs1b));
444 // match nargs
445 ✗ outBinds := matchesNargsFrontEnd(sortNargsFrontEnd(nargs1a), sortNargsFrontEnd(nargs1b), outBinds);
446 then
447 outBinds;
448
449 // TODO, handle for iterators!
450 case (Absyn.FOR_ITER_FARG(e1a, _, _), Absyn.FOR_ITER_FARG(e1b, _, _))
451 algorithm
452 ✗ outBinds := matchesFrontEnd(e1a, e1b, inAcc);
453 then
454 outBinds;
455 end match;
456 end matchesFargsFrontEnd;
457
458 public function sortNargsFrontEnd
459 input list<Absyn.NamedArg> inNargs;
460 output list<Absyn.NamedArg> outNargs;
461 algorithm
462 ✗ outNargs := List.sort(inNargs, inNargComp);
463 end sortNargsFrontEnd;
464
465 public function inNargComp
466 input Absyn.NamedArg inNarg1;
467 input Absyn.NamedArg inNarg2;
468 output Boolean isGreater;
469 protected
470 Absyn.Ident id1, id2;
471 algorithm
472 ✗ Absyn.NAMEDARG(argName = id1) := inNarg1;
473 ✗ Absyn.NAMEDARG(argName = id2) := inNarg2;
474 ✗ isGreater := intGt(stringCompare(id1, id2), 0);
475 end inNargComp;
476
477 public function matchesNargsFrontEnd
478 input list<Absyn.NamedArg> inNargs1;
479 input list<Absyn.NamedArg> inNargs2;
480 input Binds inAcc;
481 output Binds outBinds;
482 algorithm
483 outBinds := match(inNargs1, inNargs2)
484 local
485 Absyn.Ident n1a, n1b;
486 Absyn.Exp e1a, e1b;
487 list<Absyn.NamedArg> nargs1a, nargs1b;
488
489 case ({}, {}) then inAcc;
490
491 case (Absyn.NAMEDARG(n1a, e1a)::nargs1a, Absyn.NAMEDARG(n1b, e1b)::nargs1b)
492 algorithm
493 ✗ true := stringEq(n1a, n1b);
494 ✗ outBinds := matchesFrontEnd(e1a, e1b, inAcc);
495 ✗ outBinds := matchesNargsFrontEnd(nargs1a, nargs1b, outBinds);
496 then
497 outBinds;
498
499 end match;
500 end matchesNargsFrontEnd;
501
502 public function matchesExpLstLstFrontEnd
503 input list<list<Absyn.Exp>> inExps1;
504 input list<list<Absyn.Exp>> inExps2;
505 input Binds inAcc;
506 output Binds outBinds;
507 algorithm
508 outBinds := match(inExps1, inExps2)
509 local
510 list<Absyn.Exp> e1a, e1b;
511 list<list<Absyn.Exp>> exps1a, exps1b;
512
513 case ({}, {}) then inAcc;
514 case (e1a::exps1a, e1b::exps1b)
515 algorithm
516 ✗ outBinds := matchesExpLstFrontEnd(e1a, e1b, inAcc);
517 ✗ outBinds := matchesExpLstLstFrontEnd(exps1a, exps1b, outBinds);
518 then
519 outBinds;
520
521 end match;
522 end matchesExpLstLstFrontEnd;
523
524 public function isPlaceHolderFrontEnd
525 "@author: adrpo
526 returns true if the expression is a cref of the form '$REST'"
527 input Absyn.Exp inExp;
528 output Boolean isHolder;
529 algorithm
530 isHolder := match inExp
531 local
532 Boolean b;
533 Absyn.Ident name;
534
535 case Absyn.CREF(Absyn.CREF_IDENT(name, _))
536 algorithm
537 // find the string '$ at position 0
538 ✗ b := intEq(System.stringFind(name, "'$"), 0);
539 then
540 b;
541 else false;
542
543 end match;
544 end isPlaceHolderFrontEnd;
545
546
547 // backend rewrite stuff
548 // ----------------------
549 public function rewriteBackEnd
550 input DAE.Exp inExp;
551 output DAE.Exp outExp;
552 output Boolean isChanged;
553 algorithm
554 (outExp, isChanged) := match inExp
555 local
556 Rules rules;
557 Boolean b;
558
559 case _
560 algorithm
561 ✗ rules := getRulesBackEnd(getAllRules());
562 ✗ (outExp, b) := matchAndRewriteExpBackEnd(inExp, rules);
563 then
564 (outExp, b);
565
566 end match;
567 end rewriteBackEnd;
568
569 public function matchAndRewriteExpBackEnd
570 "tries to match each of the rewrite rule
571 to the input expression and bind the place
572 holders to actual expression"
573 input DAE.Exp inExp;
574 input Rules inRules;
575 output DAE.Exp outExp;
576 output Boolean changed;
577 algorithm
578 (outExp, changed) := matchcontinue inRules
579 local
580 Absyn.Exp afrom, ato;
581 DAE.Exp from, to;
582 Rules rest;
583 Binds binds;
584 Boolean b;
585
586 // nothing matched!
587 ✗ case {} then (inExp, false);
588
589 // matches the head
590 case BACKEND_RULE(afrom, ato)::_
591 algorithm
592 ✗ from := Expression.fromAbsynExp(afrom);
593 ✗ to := Expression.fromAbsynExp(ato);
594 ✗ binds as _::_ := matchesBackEnd(inExp, from, {});
595 ✗ outExp := rewriteExpBackEnd(to, binds);
596 ✗ b := boolNot(referenceEq(inExp, outExp));
597 ✗ print("BackEnd Exp: " + ExpressionBasics.printExpStr(inExp) + "\n" +
598 "BackEnd From: " + ExpressionBasics.printExpStr(from) + "\n" +
599 "BackEnd To: " + ExpressionBasics.printExpStr(to) + "\n" +
600 "BackEnd Rewrite: " + ExpressionBasics.printExpStr(outExp) + "\n---------\n");
601 ✗ then
602 (outExp, b);
603
604 // not match for the head, try next
605 case _::rest
606 algorithm
607 ✗ (outExp, b) := matchAndRewriteExpBackEnd(inExp, rest);
608 then
609 (outExp, b);
610 end matchcontinue;
611 end matchAndRewriteExpBackEnd;
612
613 public function rewriteExpBackEnd
614 input DAE.Exp inExp;
615 input Binds inBinds;
616 output DAE.Exp outExp;
617 algorithm
618 ✗ (outExp, _) := Expression.traverseExpBottomUp(inExp, replaceBindsBackEnd, inBinds);
619 end rewriteExpBackEnd;
620
621 public function replaceBindsBackEnd
622 input DAE.Exp inExp;
623 input Binds inBinds;
624 output DAE.Exp outExp;
625 output Binds outBinds;
626 algorithm
627 (outExp,outBinds) := match (inExp,inBinds)
628 local
629 DAE.Exp e1,e2;
630 Binds bnds;
631
632 case (e1 as DAE.CREF(_, _), bnds)
633 algorithm
634 ✗ e2 := replaceBindBackEnd(e1, bnds);
635 then
636 (e2, bnds);
637
638 // leave as it is
639 else (inExp,inBinds);
640
641 end match;
642 end replaceBindsBackEnd;
643
644 public function replaceBindBackEnd
645 input DAE.Exp inExp;
646 input Binds inBinds;
647 output DAE.Exp outExp;
648 protected
649 DAE.Exp e, to;
650 algorithm
651 ✗ for bind in inBinds loop
652 ✗ BACKEND_BIND(e, to) := bind;
653
654 ✗ if expEqual(inExp, e) then
655 outExp := to;
656 ✗ return;
657 end if;
658 end for;
659
660 // Couldn't find matching binding, return inExp.
661 outExp := inExp;
662 end replaceBindBackEnd;
663
664 public function matchesBackEnd
665 "@author: adrpo
666 unifies two absyn expressions and if they match
667 binds the placeholders '$1', '$2' to actual
668 expressions from inExp.
669 returns a list of BIND('$1', exp1)
670 or fails if the expressions cannot be unified"
671 input DAE.Exp inExp;
672 input DAE.Exp inUnifyWith;
673 input Binds inAcc;
674 output Binds outBinds;
675 algorithm
676 outBinds := matchcontinue(inExp, inUnifyWith)
677 local
678 DAE.Exp e1a, e2a, e1b, e2b, cond1a, cond1b;
679 DAE.Operator op1a, op1b;
680 Absyn.Path p1a, p1b;
681 list<DAE.Exp> exps1a, exps1b;
682 list<list<DAE.Exp>> expsLst1a, expsLst1b;
683 Option<DAE.Exp> oe1a, oe1b;
684
685 // we have a place holder
686 case (_, DAE.CREF(_, _))
687 algorithm
688 ✗ true := isPlaceHolderBackEnd(inUnifyWith);
689 ✗ outBinds := BACKEND_BIND(inUnifyWith, inExp)::inAcc;
690 then
691 outBinds;
692
693 // must be equal
694 case (DAE.ICONST(_), _)
695 algorithm
696 ✗ true := expEqual(inExp, inUnifyWith);
697 then
698 inAcc;
699
700 case (DAE.RCONST(_), _)
701 algorithm
702 ✗ true := expEqual(inExp, inUnifyWith);
703 then
704 inAcc;
705
706 case (DAE.SCONST(_), _)
707 algorithm
708 ✗ true := expEqual(inExp, inUnifyWith);
709 then
710 inAcc;
711
712 case (DAE.BCONST(_), _)
713 algorithm
714 ✗ true := expEqual(inExp, inUnifyWith);
715 then
716 inAcc;
717
718 // cref
719 case (DAE.CREF(_, _), _)
720 algorithm
721 ✗ true := expEqual(inExp, inUnifyWith);
722 then
723 inAcc;
724
725 case (DAE.BINARY(e1a, op1a, e2a), DAE.BINARY(e1b, op1b, e2b))
726 algorithm
727 ✗ true := operatorMatches(op1a, op1b);
728 ✗ outBinds := matchesBackEnd(e1a, e1b, inAcc);
729 ✗ outBinds := matchesBackEnd(e2a, e2b, outBinds);
730 then
731 outBinds;
732
733 case (DAE.UNARY(op1a, e1a), DAE.UNARY(op1b, e1b))
734 algorithm
735 ✗ true := operatorMatches(op1a, op1b);
736 ✗ outBinds := matchesBackEnd(e1a, e1b, inAcc);
737 then
738 outBinds;
739
740 case (DAE.LBINARY(e1a, op1a, e2a), DAE.LBINARY(e1b, op1b, e2b))
741 algorithm
742 ✗ true := operatorMatches(op1a, op1b);
743 ✗ outBinds := matchesBackEnd(e1a, e1b, inAcc);
744 ✗ outBinds := matchesBackEnd(e2a, e2b, outBinds);
745 then
746 outBinds;
747
748 case (DAE.LUNARY(op1a, e1a), DAE.LUNARY(op1b, e1b))
749 algorithm
750 ✗ true := operatorMatches(op1a, op1b);
751 ✗ outBinds := matchesBackEnd(e1a, e1b, inAcc);
752 then
753 outBinds;
754
755 case (DAE.RELATION(e1a, op1a, e2a, _, _), DAE.RELATION(e1b, op1b, e2b, _, _))
756 algorithm
757 ✗ true := operatorMatches(op1a, op1b);
758 ✗ outBinds := matchesBackEnd(e1a, e1b, inAcc);
759 ✗ outBinds := matchesBackEnd(e2a, e2b, outBinds);
760 then
761 outBinds;
762
763 case (DAE.IFEXP(cond1a, e1a, e2a), DAE.IFEXP(cond1b, e1b, e2b))
764 algorithm
765 ✗ outBinds := matchesBackEnd(cond1a, cond1b, inAcc);
766 ✗ outBinds := matchesBackEnd(e1a, e1b, outBinds);
767 ✗ outBinds := matchesBackEnd(e2a, e2b, outBinds);
768 then
769 outBinds;
770
771 case (DAE.CALL(p1a, exps1a, _), DAE.CALL(p1b, exps1b, _))
772 algorithm
773 ✗ true := AbsynUtil.pathEqual(p1a, p1b);
774 ✗ outBinds := matchesExpLstBackEnd(exps1a, exps1b, inAcc);
775 then
776 outBinds;
777
778 case (DAE.PARTEVALFUNCTION(p1a, exps1a, _, _), DAE.PARTEVALFUNCTION(p1b, exps1b, _, _))
779 algorithm
780 ✗ true := AbsynUtil.pathEqual(p1a, p1b);
781 ✗ outBinds := matchesExpLstBackEnd(exps1a, exps1b, inAcc);
782 then
783 outBinds;
784
785 case (DAE.ARRAY(array = exps1a), DAE.ARRAY(array = exps1b))
786 algorithm
787 ✗ outBinds := matchesExpLstBackEnd(exps1a, exps1b, inAcc);
788 then
789 outBinds;
790
791 case (DAE.MATRIX(matrix = expsLst1a), DAE.MATRIX(matrix = expsLst1b))
792 algorithm
793 ✗ outBinds := matchesExpLstLstBackEnd(expsLst1a, expsLst1b, inAcc);
794 then
795 outBinds;
796
797 case (DAE.RANGE(_, e1a, oe1a, e2a), DAE.RANGE(_, e1b, oe1b, e2b))
798 algorithm
799 ✗ outBinds := matchesBackEnd(e1a, e1b, inAcc);
800 ✗ outBinds := matchesExpOptBackEnd(oe1a, oe1b, outBinds);
801 ✗ outBinds := matchesBackEnd(e2a, e2b, outBinds);
802 then
803 outBinds;
804
805 case (DAE.TUPLE(exps1a), DAE.TUPLE(exps1b))
806 algorithm
807 ✗ outBinds := matchesExpLstBackEnd(exps1a, exps1b, inAcc);
808 then
809 outBinds;
810
811 case (DAE.CONS(e1a, e2a), DAE.CONS(e1b, e2b))
812 algorithm
813 ✗ outBinds := matchesBackEnd(e1a, e1b, inAcc);
814 ✗ outBinds := matchesBackEnd(e2a, e2b, outBinds);
815 then outBinds;
816
817 // TODO! support matchexp
818 case (DAE.MATCHEXPRESSION(), DAE.MATCHEXPRESSION())
819 then inAcc;
820
821 case (DAE.LIST(exps1a), DAE.LIST(exps1b))
822 algorithm
823 ✗ outBinds := matchesExpLstBackEnd(exps1a, exps1b, inAcc);
824 then
825 outBinds;
826
827 end matchcontinue;
828 end matchesBackEnd;
829
830 public function matchesExpOptBackEnd
831 input Option<DAE.Exp> inOExp1;
832 input Option<DAE.Exp> inOExp2;
833 input Binds inAcc;
834 output Binds outBinds;
835 algorithm
836 outBinds := match(inOExp1, inOExp2)
837 local DAE.Exp e1a, e1b;
838 case (NONE(), NONE()) then inAcc;
839 case (SOME(e1a), SOME(e1b))
840 algorithm
841 ✗ outBinds := matchesBackEnd(e1a, e1b, inAcc);
842 then
843 outBinds;
844 else fail();
845 end match;
846 end matchesExpOptBackEnd;
847
848 public function matchesExpLstBackEnd
849 input list<DAE.Exp> inExps1;
850 input list<DAE.Exp> inExps2;
851 input Binds inAcc;
852 output Binds outBinds;
853 algorithm
854 outBinds := match(inExps1, inExps2)
855 local
856 DAE.Exp e1a, e1b;
857 list<DAE.Exp> exps1a, exps1b;
858
859 case ({}, {}) then inAcc;
860 case (e1a::exps1a, e1b::exps1b)
861 algorithm
862 ✗ outBinds := matchesBackEnd(e1a, e1b, inAcc);
863 ✗ outBinds := matchesExpLstBackEnd(exps1a, exps1b, outBinds);
864 then
865 outBinds;
866
867 end match;
868 end matchesExpLstBackEnd;
869
870 public function matchesExpLstLstBackEnd
871 input list<list<DAE.Exp>> inExps1;
872 input list<list<DAE.Exp>> inExps2;
873 input Binds inAcc;
874 output Binds outBinds;
875 algorithm
876 outBinds := match(inExps1, inExps2)
877 local
878 list<DAE.Exp> e1a, e1b;
879 list<list<DAE.Exp>> exps1a, exps1b;
880
881 case ({}, {}) then inAcc;
882 case (e1a::exps1a, e1b::exps1b)
883 algorithm
884 ✗ outBinds := matchesExpLstBackEnd(e1a, e1b, inAcc);
885 ✗ outBinds := matchesExpLstLstBackEnd(exps1a, exps1b, outBinds);
886 then
887 outBinds;
888
889 end match;
890 end matchesExpLstLstBackEnd;
891
892 public function isPlaceHolderBackEnd
893 "@author: adrpo
894 returns true if the expression is a cref of the form '$REST'"
895 input DAE.Exp inExp;
896 output Boolean isHolder;
897 algorithm
898 isHolder := match inExp
899 local
900 Boolean b;
901 Absyn.Ident name;
902
903 case DAE.CREF(DAE.CREF_IDENT(ident = name), _)
904 algorithm
905 // find the string '$ at position 0
906 ✗ b := intEq(System.stringFind(name, "'$"), 0);
907 then
908 b;
909 else false;
910
911 end match;
912 end isPlaceHolderBackEnd;
913
914 protected function expEqual
915 input DAE.Exp e1;
916 input DAE.Exp e2;
917 output Boolean isEqual;
918 algorithm
919 isEqual := match(e1, e2)
920 local
921 Integer i;
922 Real r;
923
924 // we need additional rules here for int/real
925 case (DAE.ICONST(i), DAE.RCONST(r)) guard realEq(intReal(i), r)
926 then
927 true;
928
929 case (DAE.RCONST(r), DAE.ICONST(i)) guard realEq(intReal(i), r)
930 then
931 true;
932
933 // all others forward to expEqual
934 ✗ else ExpressionBasics.expEqual(e1, e2);
935
936 end match;
937 end expEqual;
938
939 protected function operatorMatches
940 "@author: adrpo
941 note that this unifies operators
942 op1 is DAE.Operator
943 op2 is Absyn.Operator translated to DAE.Operator"
944 input DAE.Operator op1;
945 input DAE.Operator op2;
946 output Boolean b;
947 algorithm
948 b := match(op1, op2)
949 local
950
951 case (DAE.UMINUS_ARR(),DAE.UMINUS()) then true;
952 case (DAE.ADD_ARR(),DAE.ADD()) then true;
953 case (DAE.SUB_ARR(),DAE.SUB()) then true;
954 case (DAE.MUL_ARR(),DAE.MUL()) then true;
955 case (DAE.DIV_ARR(),DAE.DIV()) then true;
956 case (DAE.MUL_ARRAY_SCALAR(),DAE.MUL()) then true;
957 case (DAE.ADD_ARRAY_SCALAR(),DAE.ADD()) then true;
958 case (DAE.SUB_SCALAR_ARRAY(),DAE.SUB()) then true;
959 case (DAE.MUL_SCALAR_PRODUCT(),DAE.MUL()) then true;
960 case (DAE.MUL_MATRIX_PRODUCT(),DAE.MUL()) then true;
961 case (DAE.DIV_SCALAR_ARRAY(),DAE.DIV()) then true;
962 case (DAE.DIV_ARRAY_SCALAR(),DAE.DIV()) then true;
963 case (DAE.POW_SCALAR_ARRAY(),DAE.POW()) then true;
964 case (DAE.POW_ARRAY_SCALAR(),DAE.POW()) then true;
965 case (DAE.POW_ARR(),DAE.POW()) then true;
966 case (DAE.POW_ARR2(),DAE.POW()) then true;
967
968 // all other forward to Expression.operatorEqual
969 ✗ else Expression.operatorEqual(op1, op2);
970
971 end match;
972 end operatorMatches;
973
974 public function loadRules
975 algorithm
976 () := match()
977 local
978 String file;
979
980 case ()
981 algorithm
982 2 file := Flags.getConfigString(Flags.REWRITE_RULES_FILE);
983 2 loadRulesFromFile(file);
984 then ();
985
986 end match;
987 end loadRules;
988
989 public function noRewriteRules
990 "@author: adrpo
991 return true if we have no rewrite rules"
992 output Boolean noRules;
993 algorithm
994 noRules := matchcontinue()
995 case ()
996 algorithm
997 ✗ NONE() := getGlobalRoot(Global.rewriteRulesIndex);
998 then
999 true;
1000 else false;
1001 end matchcontinue;
1002 end noRewriteRules;
1003
1004 public function noRewriteRulesFrontEnd
1005 "@author: adrpo
1006 return true if we have no rewrite rules for frontend"
1007 output Boolean noRules;
1008 algorithm
1009 noRules := matchcontinue()
1010
1011 case ()
1012 algorithm
1013
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 2357736 times.
✓ Branch 3 taken 2357736 times.
✗ Branch 4 not taken.
2357736 NONE() := getGlobalRoot(Global.rewriteRulesIndex);
1014 then
1015 true;
1016
1017 case ()
1018 algorithm
1019 ✗ {} := getRulesFrontEnd(getAllRules());
1020 then
1021 true;
1022
1023 else false;
1024
1025 end matchcontinue;
1026 end noRewriteRulesFrontEnd;
1027
1028 public function noRewriteRulesBackEnd
1029 "@author: adrpo
1030 return true if we have no rewrite rules for backend"
1031 output Boolean noRules;
1032 algorithm
1033 noRules := matchcontinue()
1034
1035 case ()
1036 algorithm
1037
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
2 NONE() := getGlobalRoot(Global.rewriteRulesIndex);
1038 then
1039 true;
1040
1041 case ()
1042 algorithm
1043 ✗ {} := getRulesBackEnd(getAllRules());
1044 then
1045 true;
1046
1047 else false;
1048
1049 end matchcontinue;
1050 end noRewriteRulesBackEnd;
1051
1052 public function loadRulesFromFile
1053 "load the rewite rules in the global array with index: Global.rewriteRulesIndex"
1054 input String inFile;
1055 algorithm
1056 () := matchcontinue inFile
1057 local
1058 list<GlobalScript.Statement> stmts;
1059 Rules rules;
1060 Option<Rules> oR;
1061
1062 // no file, set it to NONE
1063 case ""
1064 algorithm
1065 2 setGlobalRoot(Global.rewriteRulesIndex, NONE());
1066 then ();
1067
1068 // already loaded
1069 case _
1070 algorithm
1071 ✗ oR := getGlobalRoot(Global.rewriteRulesIndex);
1072 ✗ true := isSome(oR);
1073 then ();
1074
1075 // not loaded, load it
1076 case _
1077 algorithm
1078 ✗ NONE() := getGlobalRoot(Global.rewriteRulesIndex);
1079 ✗ GlobalScript.ISTMTS(stmts, _) := Parser.parseexp(inFile);
1080 ✗ rules := stmtsToRules(stmts, {});
1081 ✗ print("-------------\n");
1082 ✗ setGlobalRoot(Global.rewriteRulesIndex, SOME(rules));
1083 then
1084 ();
1085
1086 else
1087 algorithm
1088 ✗ Error.addInternalError("Unable to parse rewrite rules file: " + inFile, sourceInfo());
1089 ✗ setGlobalRoot(Global.rewriteRulesIndex, NONE());
1090 then
1091 ();
1092
1093 end matchcontinue;
1094 end loadRulesFromFile;
1095
1096 public function clearRules
1097 "clear the loaded rules"
1098 algorithm
1099 2 setGlobalRoot(Global.rewriteRulesIndex, NONE());
1100 end clearRules;
1101
1102 public function getAllRules
1103 "get the loaded rules"
1104 output Rules outRules;
1105 protected
1106 Option<Rules> orules;
1107 algorithm
1108 ✗ orules := getGlobalRoot(Global.rewriteRulesIndex);
1109 ✗ SOME(outRules) := orules;
1110 end getAllRules;
1111
1112 public function getRulesFrontEnd
1113 input Rules inRules;
1114 output Rules outRules;
1115 algorithm
1116 outRules := match inRules
1117 local
1118 Rules rest, lst;
1119 Rule r;
1120
1121 case {} then {};
1122
1123 case (r as FRONTEND_RULE())::rest
1124 algorithm
1125 ✗ lst := getRulesFrontEnd(rest);
1126 then r::lst;
1127
1128 ✗ case _::rest then getRulesFrontEnd(rest);
1129
1130 end match;
1131 end getRulesFrontEnd;
1132
1133 public function getRulesBackEnd
1134 input Rules inRules;
1135 output Rules outRules;
1136 algorithm
1137 outRules := match inRules
1138 local
1139 Rules rest, lst;
1140 Rule r;
1141
1142 case {} then {};
1143
1144 case (r as BACKEND_RULE())::rest
1145 algorithm
1146 ✗ lst := getRulesBackEnd(rest);
1147 then r::lst;
1148
1149 ✗ case _::rest then getRulesBackEnd(rest);
1150
1151 end match;
1152 end getRulesBackEnd;
1153
1154 protected function stmtsToRules
1155 input list<GlobalScript.Statement> inStmts;
1156 input Rules inAcc;
1157 output Rules outRules;
1158 algorithm
1159 outRules := matchcontinue inStmts
1160 local
1161 list<GlobalScript.Statement> rest;
1162 GlobalScript.Statement s;
1163 Rules acc;
1164 Absyn.Exp from, to;
1165
1166 // empty case
1167 ✗ case {} then listReverse(inAcc);
1168
1169 // frontend-rules
1170 case GlobalScript.IEXP(
1171 Absyn.CALL(
1172 Absyn.CREF_IDENT(name = "rewrite"),
1173 Absyn.FUNCTIONARGS({from, to}, {}))
1174 )::rest
1175 algorithm
1176 ✗ print("FrontEnd rule: " + Dump.printExpStr(from) + " -> " + Dump.printExpStr(to) + "\n");
1177 ✗ acc := stmtsToRules(rest, FRONTEND_RULE(from, to)::inAcc);
1178 then
1179 acc;
1180
1181 // frontend-rules
1182 case GlobalScript.IEXP(
1183 Absyn.CALL(
1184 Absyn.CREF_IDENT(name = "rewriteFrontEnd"),
1185 Absyn.FUNCTIONARGS({from, to}, {}))
1186 )::rest
1187 algorithm
1188 ✗ print("FrontEnd rule: " + Dump.printExpStr(from) + " -> " + Dump.printExpStr(to) + "\n");
1189 ✗ acc := stmtsToRules(rest, FRONTEND_RULE(from, to)::inAcc);
1190 then
1191 acc;
1192
1193 // backend-rules
1194 case GlobalScript.IEXP(
1195 Absyn.CALL(
1196 Absyn.CREF_IDENT(name = "rewriteBackEnd"),
1197 Absyn.FUNCTIONARGS({from, to}, {}))
1198 )::rest
1199 algorithm
1200 ✗ print("BackEnd rule: " + Dump.printExpStr(from) + " -> " + Dump.printExpStr(to) + "\n");
1201 ✗ acc := stmtsToRules(rest, BACKEND_RULE(from, to)::inAcc);
1202 then
1203 acc;
1204
1205 case s::_
1206 algorithm
1207 ✗ Error.addInternalError("Unable to parse rewrite rule: " + GlobalScriptDump.printIstmtStr(s), sourceInfo());
1208 ✗ then
1209 fail();
1210
1211 end matchcontinue;
1212 end stmtsToRules;
1213
1214 annotation(__OpenModelica_Interface="backend");
1215 end RewriteRules;
1216