Skip to content

Commit 2c491b7

Browse files
authored
Improve instance API Expression handling (#9862)
- Merge `array_constructor` and `reduction` into one `iterator_call` structure, and implement support for it in the OMEdit Expression class. - Implement support for ranges in the OMEdit Expression class. - Dump `size()` like a normal function. - Strip away internal compiler expressions `cast`, `box`, and `unbox` when dumping expressions to JSON. - Handle `clock` and `typename` expressions like crefs in the OMEdit Expression class. - Also check the `toQString` results in the Expression test case.
1 parent 0d30620 commit 2c491b7

File tree

5 files changed

+297
-147
lines changed

5 files changed

+297
-147
lines changed

OMCompiler/Compiler/NFFrontEnd/NFCall.mo

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -851,7 +851,8 @@ public
851851

852852
case TYPED_ARRAY_CONSTRUCTOR()
853853
algorithm
854-
json := JSON.addPair("$kind", JSON.makeString("array_constructor"), json);
854+
json := JSON.addPair("$kind", JSON.makeString("iterator_call"), json);
855+
json := JSON.addPair("name", JSON.makeString("$array"), json);
855856
json := JSON.addPair("exp", Expression.toJSON(call.exp), json);
856857
json := JSON.addPair("iterators", iterators_json(call.iters), json);
857858
then
@@ -860,7 +861,7 @@ public
860861
case TYPED_REDUCTION()
861862
algorithm
862863
path := Function.nameConsiderBuiltin(call.fn);
863-
json := JSON.addPair("$kind", JSON.makeString("reduction"), json);
864+
json := JSON.addPair("$kind", JSON.makeString("iterator_call"), json);
864865
json := JSON.addPair("name", JSON.makeString(AbsynUtil.pathString(path)), json);
865866
json := JSON.addPair("exp", Expression.toJSON(call.exp), json);
866867
json := JSON.addPair("iterators", iterators_json(call.iters), json);

OMCompiler/Compiler/NFFrontEnd/NFExpression.mo

Lines changed: 9 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5944,11 +5944,14 @@ public
59445944
case Expression.SIZE()
59455945
algorithm
59465946
json := JSON.emptyObject();
5947-
json := JSON.addPair("$kind", JSON.makeString("size"), json);
5948-
json := JSON.addPair("exp", toJSON(exp.exp), json);
5947+
json := JSON.addPair("$kind", JSON.makeString("call"), json);
5948+
json := JSON.addPair("name", JSON.makeString("size"), json);
59495949

59505950
if isSome(exp.dimIndex) then
5951-
json := JSON.addPair("index", toJSON(Util.getOption(exp.dimIndex)), json);
5951+
JSON.addPair("arguments",
5952+
JSON.makeArray({toJSON(exp.exp), toJSON(Util.getOption(exp.dimIndex))}), json);
5953+
else
5954+
JSON.addPair("arguments", JSON.makeArray({toJSON(exp.exp)}), json);
59525955
end if;
59535956
then
59545957
json;
@@ -6011,30 +6014,9 @@ public
60116014
then
60126015
json;
60136016

6014-
case Expression.CAST()
6015-
algorithm
6016-
json := JSON.emptyObject();
6017-
json := JSON.addPair("$kind", JSON.makeString("cast"), json);
6018-
json := JSON.addPair("type", JSON.makeString(Type.toString(exp.ty)), json);
6019-
json := JSON.addPair("exp", toJSON(exp.exp), json);
6020-
then
6021-
json;
6022-
6023-
case Expression.BOX()
6024-
algorithm
6025-
json := JSON.emptyObject();
6026-
json := JSON.addPair("$kind", JSON.makeString("box"), json);
6027-
json := JSON.addPair("exp", toJSON(exp.exp), json);
6028-
then
6029-
json;
6030-
6031-
case Expression.UNBOX()
6032-
algorithm
6033-
json := JSON.emptyObject();
6034-
json := JSON.addPair("$kind", JSON.makeString("unbox"), json);
6035-
json := JSON.addPair("exp", toJSON(exp.exp), json);
6036-
then
6037-
json;
6017+
case Expression.CAST() then toJSON(exp.exp);
6018+
case Expression.BOX() then toJSON(exp.exp);
6019+
case Expression.UNBOX() then toJSON(exp.exp);
60386020

60396021
case Expression.SUBSCRIPTED_EXP()
60406022
algorithm

OMEdit/OMEditLIB/FlatModelica/Expression.cpp

Lines changed: 230 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,28 @@ namespace FlatModelica
653653
std::vector<Expression> _elements;
654654
};
655655

656+
class Range : public ExpressionBase
657+
{
658+
public:
659+
Range(Expression start, Expression step, Expression stop)
660+
: _start(std::move(start)), _step(std::move(step)), _stop(std::move(stop)) {}
661+
662+
Range(const QJsonObject &value);
663+
664+
std::unique_ptr<ExpressionBase> clone() const override { return std::make_unique<Range>(*this); }
665+
Expression eval(const Expression::VariableEvaluator &var_eval) const override;
666+
667+
bool isLiteral() const override;
668+
669+
void print(std::ostream &os) const override;
670+
QJsonValue serialize() const override;
671+
672+
private:
673+
Expression _start;
674+
Expression _step;
675+
Expression _stop;
676+
};
677+
656678
class Call : public ExpressionBase
657679
{
658680
public:
@@ -682,6 +704,46 @@ namespace FlatModelica
682704
bool _is_record;
683705
};
684706

707+
class Iterator
708+
{
709+
public:
710+
Iterator(std::string name, Expression range)
711+
: _name(std::move(name)), _range(std::move(range)) {}
712+
713+
Iterator(const QJsonValue &value);
714+
715+
const std::string& name() const { return _name; }
716+
const Expression& range() const { return _range; }
717+
718+
QJsonValue serialize() const;
719+
720+
private:
721+
std::string _name;
722+
Expression _range;
723+
};
724+
725+
class IteratorCall : public ExpressionBase
726+
{
727+
public:
728+
IteratorCall(std::string name, Expression exp, std::vector<Iterator> iterators)
729+
: _name(std::move(name)), _exp(std::move(exp)), _iterators(std::move(iterators)) {}
730+
731+
IteratorCall(const QJsonObject &value);
732+
733+
std::unique_ptr<ExpressionBase> clone() const override { return std::make_unique<IteratorCall>(*this); }
734+
Expression eval(const Expression::VariableEvaluator &var_eval) const override;
735+
736+
bool isLiteral() const override { return false; }
737+
738+
void print(std::ostream &os) const override;
739+
QJsonValue serialize() const override;
740+
741+
private:
742+
std::string _name;
743+
Expression _exp;
744+
std::vector<Iterator> _iterators;
745+
};
746+
685747
class Binary : public ExpressionBase
686748
{
687749
public:
@@ -1157,22 +1219,17 @@ namespace FlatModelica
11571219
if (kind.isString()) {
11581220
switch (djb2_qHash(kind.toString().data())) {
11591221
case djb2_hash("enum"): return std::make_unique<Enum>(value);
1160-
//case djb2_hash("clock"): return std::make_unique<Clock>(value);
1222+
case djb2_hash("clock"): return std::make_unique<Cref>(value);
11611223
case djb2_hash("cref"): return std::make_unique<Cref>(value);
1162-
//case djb2_hash("typename"): return std::make_unique<Typename>(value);
1163-
//case djb2_hash("range"): return std::make_unique<Range>(value);
1224+
case djb2_hash("typename"): return std::make_unique<Cref>(value);
1225+
case djb2_hash("range"): return std::make_unique<Range>(value);
11641226
//case djb2_hash("tuple"): return std::make_unique<Tuple>(value);
11651227
case djb2_hash("record"): return std::make_unique<Call>(value, true);
11661228
case djb2_hash("call"): return std::make_unique<Call>(value, false);
1167-
//case djb2_hash("array_constructor"): return std::make_unique<ArrayConstructor>(value);
1168-
//case djb2_hash("reduction"): return std::make_unique<Reduction>(value);
1169-
//case djb2_hash("size"): return std::make_unique<Size>(value);
1229+
case djb2_hash("iterator_call"): return std::make_unique<IteratorCall>(value);
11701230
case djb2_hash("binary_op"): return std::make_unique<Binary>(value);
11711231
case djb2_hash("unary_op"): return std::make_unique<Unary>(value);
11721232
case djb2_hash("if"): return std::make_unique<IfExp>(value);
1173-
//case djb2_hash("cast"): return std::make_unique<Cast>(value);
1174-
//case djb2_hash("box"): return std::make_unique<Box>(value);
1175-
//case djb2_hash("unbox"): return std::make_unique<Unbox>(value);
11761233
//case djb2_hash("sub"): return std::make_unique<Subscripted>(value);
11771234
//case djb2_hash("tuple_element"): return std::make_unique<TupleElement>(value);
11781235
//case djb2_hash("record_element"): return std::make_unique<RecordElement>(value);
@@ -1466,6 +1523,69 @@ namespace FlatModelica
14661523
return Expression(std::move(elems));
14671524
}
14681525

1526+
Range::Range(const QJsonObject &value)
1527+
{
1528+
auto start = value.find("start");
1529+
1530+
if (start == value.end()) {
1531+
throw json_error("Expression: missing range start in ", value);
1532+
}
1533+
1534+
_start.deserialize(*start);
1535+
1536+
auto stop = value.find("stop");
1537+
1538+
if (stop == value.end()) {
1539+
throw json_error("Expression: missing range stop in ", value);
1540+
}
1541+
1542+
_stop.deserialize(*stop);
1543+
1544+
auto step = value.find("step");
1545+
1546+
if (step != value.end()) {
1547+
_step.deserialize(*step);
1548+
}
1549+
}
1550+
1551+
Expression Range::eval(const Expression::VariableEvaluator &var_eval) const
1552+
{
1553+
auto start = _start.evaluate(var_eval);
1554+
auto stop = _stop.evaluate(var_eval);
1555+
auto step = _step.isNull() ? Expression() : _step.evaluate(var_eval);
1556+
return Expression(std::make_unique<Range>(std::move(start), std::move(step), std::move(stop)));
1557+
}
1558+
1559+
bool Range::isLiteral() const
1560+
{
1561+
return _start.isLiteral() && _step.isLiteral() && _stop.isLiteral();
1562+
}
1563+
1564+
void Range::print(std::ostream &os) const
1565+
{
1566+
os << _start << ':';
1567+
1568+
if (!_step.isNull()) {
1569+
os << _step << ':';
1570+
}
1571+
1572+
os << _stop;
1573+
}
1574+
1575+
QJsonValue Range::serialize() const
1576+
{
1577+
QJsonObject obj;
1578+
obj.insert("$kind", "range");
1579+
obj.insert("start", _start.serialize());
1580+
1581+
if (!_step.isNull()) {
1582+
obj.insert("step", _step.serialize());
1583+
}
1584+
1585+
obj.insert("stop", _stop.serialize());
1586+
return obj;
1587+
}
1588+
14691589
Call::Call(const QJsonObject &value, bool isRecord)
14701590
: _is_record(isRecord)
14711591
{
@@ -1615,6 +1735,107 @@ namespace FlatModelica
16151735
return Expression(std::make_unique<Call>(name, std::move(args)));
16161736
}
16171737

1738+
Iterator::Iterator(const QJsonValue &value)
1739+
{
1740+
if (!value.isObject()) {
1741+
throw json_error("Expression: invalid iterator expression: ", value);
1742+
}
1743+
1744+
auto obj = value.toObject();
1745+
auto name = obj["name"];
1746+
1747+
if (!name.isString()) {
1748+
throw json_error("Expression: invalid iterator name: ", name);
1749+
}
1750+
1751+
_name = name.toString().toStdString();
1752+
1753+
auto range = obj.find("range");
1754+
1755+
if (range == obj.end()) {
1756+
throw json_error("Expression: missing iterator range in ", value);
1757+
}
1758+
1759+
_range.deserialize(*range);
1760+
}
1761+
1762+
QJsonValue Iterator::serialize() const
1763+
{
1764+
QJsonObject obj;
1765+
obj.insert("name", _name.c_str());
1766+
obj.insert("range", _range.serialize());
1767+
return obj;
1768+
}
1769+
1770+
std::ostream& operator<< (std::ostream &os, const Iterator &i)
1771+
{
1772+
os << i.name() << " in " << i.range();
1773+
return os;
1774+
}
1775+
1776+
IteratorCall::IteratorCall(const QJsonObject &value)
1777+
{
1778+
auto name = value["name"];
1779+
1780+
if (!name.isString()) {
1781+
throw json_error("Expression: invalid JSON iterator call name: ", name);
1782+
}
1783+
1784+
_name = name.toString().toStdString();
1785+
_exp.deserialize(value["exp"]);
1786+
1787+
auto iters = value["iterators"];
1788+
1789+
if (!iters.isArray()) {
1790+
throw json_error("Expression: invalid JSON iterator call iterators: ", iters);
1791+
}
1792+
1793+
for (const auto &i: iters.toArray()) {
1794+
_iterators.emplace_back(i);
1795+
}
1796+
}
1797+
1798+
Expression IteratorCall::eval(const Expression::VariableEvaluator &var_eval) const
1799+
{
1800+
return Expression(std::make_unique<IteratorCall>(*this));
1801+
}
1802+
1803+
void IteratorCall::print(std::ostream &os) const
1804+
{
1805+
bool is_array = _name == "$array";
1806+
1807+
if (is_array) {
1808+
os << '{';
1809+
} else {
1810+
os << _name << '(';
1811+
}
1812+
1813+
os << _exp << " for ";
1814+
1815+
for (auto it = _iterators.begin(); it != _iterators.end(); ++it) {
1816+
if (it != _iterators.begin()) os << ", ";
1817+
os << *it;
1818+
}
1819+
1820+
os << (is_array ? '}' : ')');
1821+
}
1822+
1823+
QJsonValue IteratorCall::serialize() const
1824+
{
1825+
QJsonObject obj;
1826+
obj.insert("$kind", "iterator_call");
1827+
obj.insert("name", _name.c_str());
1828+
obj.insert("exp", _exp.serialize());
1829+
1830+
QJsonArray iters;
1831+
for (auto &i: _iterators) {
1832+
iters.push_back(i.serialize());
1833+
}
1834+
obj.insert("iterators", std::move(iters));
1835+
1836+
return obj;
1837+
}
1838+
16181839
Binary::Binary(const QJsonObject &value)
16191840
{
16201841
_e1.deserialize(value["lhs"]);

0 commit comments

Comments
 (0)