Skip to content
This repository was archived by the owner on May 18, 2019. It is now read-only.

Commit 69ee163

Browse files
perostOpenModelica-Hudson
authored andcommitted
[NF] Subscripting improvements.
- Implemented basic handling of slices in Expression.applySubscript. - Implemented missing cases for Real ranges in RangeIterator. - Added the concept of invalid ranges to RangeIterator to allow it to fail gracefully on non-expandable ranges. - Improved detection of too small step size in Real ranges. Belonging to [master]: - #2308 - OpenModelica/OpenModelica-testsuite#892
1 parent 13b595d commit 69ee163

File tree

8 files changed

+135
-46
lines changed

8 files changed

+135
-46
lines changed

Compiler/NFFrontEnd/NFCall.mo

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,7 @@ uniontype Call
684684
b::b_list := b_list;
685685
// If the argument is supposed to be vectorized
686686
if b then
687-
vect_args := Expression.applySubscript(arg, Subscript.INDEX(exp))::vect_args;
687+
vect_args := Expression.applyIndexSubscript(exp, arg)::vect_args;
688688
else
689689
vect_args := arg::vect_args;
690690
end if;

Compiler/NFFrontEnd/NFCeval.mo

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ algorithm
137137
binding := Component.getBinding(InstNode.component(c));
138138
exp1 := evalBinding(binding, exp, target);
139139
then
140-
Expression.applySubscripts(exp1, cref.subscripts);
140+
Expression.applySubscripts(cref.subscripts, exp1);
141141

142142
case Expression.TYPENAME()
143143
then evalTypename(exp.ty, exp, target);

Compiler/NFFrontEnd/NFExpression.mo

Lines changed: 75 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ protected
4141
import RangeIterator = NFRangeIterator;
4242
import NFPrefixes.Variability;
4343
import Prefixes = NFPrefixes;
44+
import MetaModelica.Dangerous.listReverseInPlace;
4445

4546
public
4647
import Absyn.Path;
@@ -574,42 +575,50 @@ public
574575
end realValue;
575576

576577
function applySubscripts
577-
input output Expression exp;
578578
input list<Subscript> subscripts;
579+
input output Expression exp;
579580
algorithm
580581
for sub in subscripts loop
581-
exp := applySubscript(exp, sub);
582+
exp := applySubscript(sub, exp);
582583
end for;
583584
end applySubscripts;
584585

585586
function applySubscript
586-
input output Expression exp;
587587
input Subscript sub;
588+
input Expression exp;
589+
output Expression subscriptedExp;
590+
algorithm
591+
subscriptedExp := match sub
592+
case Subscript.INDEX() then applyIndexSubscript(sub.index, exp);
593+
case Subscript.SLICE() then applySliceSubscript(sub.slice, exp);
594+
case Subscript.WHOLE() then exp;
595+
else
596+
algorithm
597+
Error.assertion(false, getInstanceName() + " got untyped subscript " +
598+
Subscript.toString(sub), sourceInfo());
599+
then
600+
fail();
601+
end match;
602+
end applySubscript;
603+
604+
function applyIndexSubscript
605+
input Expression indexExp;
606+
input output Expression exp;
588607
protected
589608
Integer index;
590609
Boolean is_scalar_const;
591610
Expression texp;
592611
Type exp_ty;
593612
algorithm
594-
595-
if not Subscript.isScalar(sub) then
596-
// We need to properly compute the resulting type. Just unlifting the type is not enough if sub is not scalar.
597-
// Use Type.subscript to compute the type and make sure SUPSCRIPTED_EXP doesn't result in complicated types.
598-
Error.assertion(false, getInstanceName() + ": Application of non-scalar subs on expressoins not implemented. "
599-
+ "Exp: " + toString(exp)
600-
+ ", Sub: "+ Subscript.toString(sub)
601-
, sourceInfo());
602-
fail();
603-
end if;
604-
is_scalar_const := Subscript.isScalarConst(sub);
613+
is_scalar_const := Expression.isScalarConst(indexExp);
605614

606615
// check exp has array type. Don't apply subs to scalar exp.
607616
exp_ty := typeOf(exp);
608617
if not Type.isArray(exp_ty) then
609618
Error.assertion(false, getInstanceName() + ": Application of subs on non-array expressoin not allowed. "
610619
+ "Exp: " + toString(exp)
611620
+ ", Exp type: " + Type.toString(exp_ty)
612-
+ ", Sub: " + Subscript.toString(sub)
621+
+ ", Sub: " + toString(indexExp)
613622
, sourceInfo());
614623
fail();
615624
end if;
@@ -619,7 +628,7 @@ public
619628
ComponentRef cref;
620629

621630
case CREF() algorithm
622-
cref := ComponentRef.addSubscript(sub, exp.cref);
631+
cref := ComponentRef.addSubscript(Subscript.INDEX(indexExp), exp.cref);
623632
texp := CREF(Type.unliftArray(exp.ty), cref);
624633
then texp;
625634

@@ -630,25 +639,70 @@ public
630639
// Do we want to create SUBSCRIPTED_EXP and go through the ASUB hell of the old FrontEnd?
631640
// k = {1,i,2}[j];
632641
if is_scalar_const then
633-
index := Subscript.toInteger(sub);
642+
index := Expression.toInteger(indexExp);
634643
texp := listGet(exp.elements, index);
635644
else
636-
texp := SUBSCRIPTED_EXP(exp, {Subscript.toExp(sub)}, Type.unliftArray(exp.ty));
645+
texp := SUBSCRIPTED_EXP(exp, {indexExp}, Type.unliftArray(exp.ty));
637646
// Error.assertion(false, getInstanceName() + " failed on " + Subscript.toString(sub), sourceInfo());
638647
// fail();
639648
end if;
640649
then texp;
641650

642651
case SUBSCRIPTED_EXP() algorithm
643-
texp := SUBSCRIPTED_EXP(exp.exp, listAppend(exp.subscripts,{Subscript.toExp(sub)}), Type.unliftArray(exp.ty));
652+
texp := SUBSCRIPTED_EXP(exp.exp, listAppend(exp.subscripts,{indexExp}), Type.unliftArray(exp.ty));
644653
then texp;
645654

646655
else algorithm
647-
texp := SUBSCRIPTED_EXP(exp, {Subscript.toExp(sub)}, Type.unliftArray(exp_ty));
656+
texp := SUBSCRIPTED_EXP(exp, {indexExp}, Type.unliftArray(exp_ty));
648657
then texp;
649658

650659
end match;
651-
end applySubscript;
660+
end applyIndexSubscript;
661+
662+
function applySliceSubscript
663+
input Expression slice;
664+
input Expression exp;
665+
output Expression subscriptedExp;
666+
protected
667+
list<Expression> expl;
668+
RangeIterator iter;
669+
Expression e;
670+
Type ty;
671+
ComponentRef cref;
672+
algorithm
673+
// Replace the last dimension of the expression type with the dimension of the slice type.
674+
ty := Type.liftArrayLeft(Type.unliftArray(typeOf(exp)), Type.nthDimension(typeOf(slice), 1));
675+
iter := RangeIterator.fromExp(slice);
676+
677+
if RangeIterator.isValid(iter) then
678+
// If the slice is a range of known size, apply each subscript in the slice
679+
// to the expression and create a new array from the resulting elements.
680+
expl := {};
681+
682+
while RangeIterator.hasNext(iter) loop
683+
(iter, e) := RangeIterator.next(iter);
684+
e := applyIndexSubscript(e, exp);
685+
expl := e :: expl;
686+
end while;
687+
688+
ty := Type.liftArrayLeft(Type.unliftArray(typeOf(exp)), Dimension.fromInteger(listLength(expl)));
689+
subscriptedExp := ARRAY(ty, listReverseInPlace(expl));
690+
else
691+
// If the slice can't be expanded, just add it to the expression as a slice subscript.
692+
subscriptedExp := match exp
693+
case CREF()
694+
algorithm
695+
cref := ComponentRef.addSubscript(Subscript.SLICE(slice), exp.cref);
696+
then
697+
CREF(ty, cref);
698+
699+
case SUBSCRIPTED_EXP()
700+
then SUBSCRIPTED_EXP(exp.exp, listAppend(exp.subscripts, {slice}), ty);
701+
702+
else SUBSCRIPTED_EXP(exp, {slice}, ty);
703+
end match;
704+
end if;
705+
end applySliceSubscript;
652706

653707
function arrayFromList
654708
input list<Expression> inExps;

Compiler/NFFrontEnd/NFFlatten.mo

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ algorithm
429429

430430
if binding_level > 0 then
431431
subs := List.flatten(ComponentRef.subscriptsN(prefix, InstNode.level(component) - binding_level));
432-
binding.bindingExp := Expression.applySubscripts(binding.bindingExp, subs);
432+
binding.bindingExp := Expression.applySubscripts(subs, binding.bindingExp);
433433
end if;
434434
then
435435
();

Compiler/NFFrontEnd/NFRangeIterator.mo

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,33 @@ public
4747
record REAL_RANGE
4848
Real start;
4949
Real stepsize;
50-
Real stop;
50+
Integer current;
51+
Integer steps;
5152
end REAL_RANGE;
5253

5354
record ARRAY_RANGE
5455
list<Expression> values;
5556
end ARRAY_RANGE;
5657

58+
record INVALID_RANGE
59+
Expression exp;
60+
end INVALID_RANGE;
61+
62+
function isValid
63+
input RangeIterator iterator;
64+
output Boolean isValid;
65+
algorithm
66+
isValid := match iterator
67+
case INVALID_RANGE() then false;
68+
else true;
69+
end match;
70+
end isValid;
71+
5772
function fromExp
73+
"Returns a RangeIterator created from the given expression. If the
74+
expression isn't an expression that can be expanded into elements an
75+
invalid range will be returned that will trigger an assertion when used.
76+
The valididity of the returned iterator can be checked with isValid."
5877
input Expression exp;
5978
output RangeIterator iterator;
6079
algorithm
@@ -72,7 +91,8 @@ public
7291
case Expression.RANGE(start = Expression.INTEGER(istart),
7392
step = SOME(Expression.INTEGER(istep)),
7493
stop = Expression.INTEGER(istop))
75-
then INT_RANGE(istart, istep, istop);
94+
then
95+
INT_RANGE(istart, istep, istop);
7696

7797
case Expression.RANGE(start = Expression.INTEGER(istart),
7898
step = NONE(),
@@ -82,12 +102,12 @@ public
82102
case Expression.RANGE(start = Expression.REAL(rstart),
83103
step = SOME(Expression.REAL(rstep)),
84104
stop = Expression.REAL(rstop))
85-
then REAL_RANGE(rstart, rstep, rstop);
105+
then REAL_RANGE(rstart, rstep, 0, Util.realRangeSize(rstart, rstep, rstop));
86106

87107
case Expression.RANGE(start = Expression.REAL(rstart),
88108
step = NONE(),
89109
stop = Expression.REAL(rstop))
90-
then REAL_RANGE(rstart, 1.0, rstop);
110+
then REAL_RANGE(rstart, 1.0, 0, Util.realRangeSize(rstart, 1.0, rstop));
91111

92112
case Expression.RANGE(start = Expression.ENUM_LITERAL(ty = ty, index = istart),
93113
step = NONE(),
@@ -111,11 +131,7 @@ public
111131
then
112132
ARRAY_RANGE(values);
113133

114-
else
115-
algorithm
116-
Error.assertion(false, getInstanceName() + " got unknown range", sourceInfo());
117-
then
118-
fail();
134+
else INVALID_RANGE(exp);
119135

120136
end match;
121137
end fromExp;
@@ -160,13 +176,26 @@ public
160176
then
161177
nextExp;
162178

179+
case REAL_RANGE()
180+
algorithm
181+
nextExp := Expression.REAL(iterator.start + iterator.stepsize * iterator.current);
182+
iterator.current := iterator.current + 1;
183+
then
184+
nextExp;
185+
163186
case ARRAY_RANGE()
164187
algorithm
165188
nextExp := listHead(iterator.values);
166189
iterator.values := listRest(iterator.values);
167190
then
168191
nextExp;
169192

193+
case INVALID_RANGE()
194+
algorithm
195+
Error.assertion(false, getInstanceName() + " got invalid range " +
196+
Expression.toString(iterator.exp), sourceInfo());
197+
then
198+
fail();
170199
end match;
171200
end next;
172201

@@ -176,7 +205,14 @@ public
176205
algorithm
177206
hasNext := match iterator
178207
case INT_RANGE() then iterator.current <= iterator.last;
208+
case REAL_RANGE() then iterator.current < iterator.steps;
179209
case ARRAY_RANGE() then not listEmpty(iterator.values);
210+
case INVALID_RANGE()
211+
algorithm
212+
Error.assertion(false, getInstanceName() + " got invalid range " +
213+
Expression.toString(iterator.exp), sourceInfo());
214+
then
215+
fail();
180216
end match;
181217
end hasNext;
182218

Compiler/NFFrontEnd/NFSubscript.mo

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ protected
3838
import SimplifyExp = NFSimplifyExp;
3939
import Type = NFType;
4040
import RangeIterator = NFRangeIterator;
41+
import Dump;
4142

4243
public
4344
import Expression = NFExpression;
@@ -147,9 +148,7 @@ public
147148
output Boolean isScalarConst;
148149
algorithm
149150
isScalarConst := match sub
150-
case INDEX(Expression.INTEGER()) then true;
151-
case INDEX(Expression.BOOLEAN()) then true;
152-
case INDEX(Expression.ENUM_LITERAL()) then true;
151+
case INDEX() then Expression.isScalarConst(sub.index);
153152
else false;
154153
end match;
155154
end isScalarConst;
@@ -290,6 +289,7 @@ public
290289
output String string;
291290
algorithm
292291
string := match subscript
292+
case RAW_SUBSCRIPT() then Dump.printSubscriptStr(subscript.subscript);
293293
case UNTYPED() then Expression.toString(subscript.exp);
294294
case INDEX() then Expression.toString(subscript.index);
295295
case SLICE() then Expression.toString(subscript.slice);

Compiler/NFFrontEnd/NFTypeCheck.mo

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1985,7 +1985,7 @@ algorithm
19851985
algorithm
19861986
// Don't allow infinite ranges.
19871987
if step == 0 then
1988-
Error.addSourceMessageAndFail(Error.RANGE_ZERO_STEP, {}, info);
1988+
Error.addSourceMessageAndFail(Error.RANGE_TOO_SMALL_STEP, {String(step)}, info);
19891989
end if;
19901990
then
19911991
Dimension.fromInteger(max(intDiv(stopExp.value - startExp.value, step) + 1, 0));
@@ -2003,18 +2003,17 @@ function getRangeTypeReal
20032003
algorithm
20042004
dim := match (startExp, stepExp, stopExp)
20052005
local
2006-
Real step;
2006+
Real start, step;
20072007

20082008
case (Expression.REAL(), NONE(), Expression.REAL())
20092009
then Dimension.fromInteger(Util.realRangeSize(startExp.value, 1.0, stopExp.value));
20102010

2011-
case (Expression.REAL(), SOME(Expression.REAL(value = step)), Expression.REAL())
2011+
case (Expression.REAL(value = start), SOME(Expression.REAL(value = step)), Expression.REAL())
20122012
algorithm
2013-
// The old inst checked that step > 1e-14, but that's actually ok if
2014-
// start and stop are also small. We could maybe check that the range
2015-
// doesn't become too large, but then we'd have to define 'too large'.
2016-
if step == 0.0 then
2017-
Error.addSourceMessageAndFail(Error.RANGE_ZERO_STEP, {}, info);
2013+
// Check that adding step to start actually produces a different value,
2014+
// otherwise the step size is too small.
2015+
if start == start + step then
2016+
Error.addSourceMessageAndFail(Error.RANGE_TOO_SMALL_STEP, {String(step)}, info);
20182017
end if;
20192018
then
20202019
Dimension.fromInteger(Util.realRangeSize(startExp.value, step, stopExp.value));

Compiler/Util/Error.mo

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -718,8 +718,8 @@ public constant Message INITIAL_CALL_WARNING = MESSAGE(294, TRANSLATION(), WARNI
718718
Util.gettext("The standard says that initial() may only be used as a when condition (when initial() or when {..., initial(), ...}), but got condition %s."));
719719
public constant Message RANGE_TYPE_MISMATCH = MESSAGE(295, TRANSLATION(), ERROR(),
720720
Util.gettext("Type mismatch in range: '%s' of type\n %s\nis not type compatible with '%s' of type\n %s"));
721-
public constant Message RANGE_ZERO_STEP = MESSAGE(296, TRANSLATION(), ERROR(),
722-
Util.gettext("Range may not have a step size of 0."));
721+
public constant Message RANGE_TOO_SMALL_STEP = MESSAGE(296, TRANSLATION(), ERROR(),
722+
Util.gettext("Step size %s in range is too small."));
723723
public constant Message RANGE_INVALID_STEP = MESSAGE(297, TRANSLATION(),
724724
ERROR(),
725725
Util.gettext("Range of type %s may not specify a step size."));

0 commit comments

Comments
 (0)