+From 6225d8585d215569c4a919171bea1915c306d1c8 Mon Sep 17 00:00:00 2001
+From: Andreas Grois <andi@grois.info>
+Date: Mon, 25 Sep 2023 21:26:23 +0200
+Subject: [PATCH] Make ERM compile again.
+
+This is not a proper clean up. It does not bring the code up to the
+current state of the rest of the codebase. However, the module now
+compiles again.
+---
+ scripting/erm/ERMInterpreter.cpp | 279 +++++++++++++++++--------------
+ scripting/erm/ERMInterpreter.h | 13 +-
+ scripting/erm/ERMParser.h | 1 +
+ 3 files changed, 151 insertions(+), 142 deletions(-)
+
+diff --git a/scripting/erm/ERMInterpreter.cpp b/scripting/erm/ERMInterpreter.cpp
+index 663cb35722..e4f60105ab 100644
+--- a/scripting/erm/ERMInterpreter.cpp
++++ b/scripting/erm/ERMInterpreter.cpp
+@@ -163,7 +163,7 @@ namespace ERMConverter
+ Variable operator()(const TVarExpNotMacro & val) const\r
+ {\r
+ if(val.val.has_value())\r
+- return Variable(val.varsym, val.val.get());\r
++ return Variable(val.varsym, *val.val);\r
+ else\r
+ return Variable(val.varsym, 0);\r
+ }\r
+@@ -392,7 +392,7 @@ namespace ERMConverter
+ \r
+ if(trig.params.has_value())\r
+ {\r
+- for(auto & p : trig.params.get())\r
++ for(auto & p : *trig.params)\r
+ optionParams.push_back(std::visit(BodyOption(), p));\r
+ }\r
+ \r
+@@ -572,7 +572,7 @@ namespace ERMConverter
+ {\r
+ if(option.params.has_value())\r
+ {\r
+- for(auto & p : option.params.get())\r
++ for(auto & p : *option.params)\r
+ {\r
+ std::string macroName = std::visit(MC_S(), p);\r
+ \r
+@@ -739,7 +739,7 @@ namespace ERMConverter
+ \r
+ if(trig.params.has_value())\r
+ {\r
+- for(auto & p : trig.params.get())\r
++ for(auto & p : *trig.params)\r
+ optionParams.push_back(std::visit(BodyOption(), p));\r
+ }\r
+ \r
+@@ -759,10 +759,10 @@ namespace ERMConverter
+ break;\r
+ case 'H': //checking if string is empty\r
+ {\r
+- if(!trig.params.has_value() || trig.params.get().size() != 1)\r
++ if(!trig.params.has_value() || trig.params->size() != 1)\r
+ throw EScriptExecError("VR:H option takes exactly 1 parameter!");\r
+ \r
+- std::string opt = std::visit(VR_H(), trig.params.get()[0]);\r
++ std::string opt = std::visit(VR_H(), (*trig.params)[0]);\r
+ boost::format fmt("ERM.VR(%s):H(%s)");\r
+ fmt % v.str() % opt;\r
+ putLine(fmt.str());\r
+@@ -770,10 +770,10 @@ namespace ERMConverter
+ break;\r
+ case 'U':\r
+ {\r
+- if(!trig.params.has_value() || trig.params.get().size() != 1)\r
++ if(!trig.params.has_value() || trig.params->size() != 1)\r
+ throw EScriptExecError("VR:H/U need 1 parameter!");\r
+ \r
+- std::string opt = std::visit(VR_S(), trig.params.get()[0]);\r
++ std::string opt = std::visit(VR_S(), (*trig.params)[0]);\r
+ boost::format fmt("ERM.VR(%s):%c(%s)");\r
+ fmt % v.str() % (trig.optionCode) % opt;\r
+ putLine(fmt.str());\r
+@@ -781,10 +781,10 @@ namespace ERMConverter
+ break;\r
+ case 'M': //string operations\r
+ {\r
+- if(!trig.params.has_value() || trig.params.get().size() < 2)\r
++ if(!trig.params.has_value() || trig.params->size() < 2)\r
+ throw EScriptExecError("VR:M needs at least 2 parameters!");\r
+ \r
+- std::string opt = std::visit(VR_X(), trig.params.get()[0]);\r
++ std::string opt = std::visit(VR_X(), (*trig.params)[0]);\r
+ int paramIndex = 1;\r
+ \r
+ if(opt == "3")\r
+@@ -795,16 +795,16 @@ namespace ERMConverter
+ }\r
+ else\r
+ {\r
+- auto target = std::visit(VR_X(), trig.params.get()[paramIndex++]);\r
++ auto target = std::visit(VR_X(), (*trig.params)[paramIndex++]);\r
+ \r
+ boost::format fmt("%s = ERM.VR(%s):M%s(");\r
+ fmt % target % v.str() % opt;\r
+ put(fmt.str());\r
+ }\r
+ \r
+- for(int i = paramIndex; i < trig.params.get().size(); i++)\r
++ for(int i = paramIndex; i < trig.params->size(); i++)\r
+ {\r
+- opt = std::visit(VR_X(), trig.params.get()[i]);\r
++ opt = std::visit(VR_X(), (*trig.params)[i]);\r
+ if(i > paramIndex) put(",");\r
+ put(opt);\r
+ }\r
+@@ -814,10 +814,10 @@ namespace ERMConverter
+ break;\r
+ case 'X': //bit xor\r
+ {\r
+- if(!trig.params.has_value() || trig.params.get().size() != 1)\r
++ if(!trig.params.has_value() || trig.params->size() != 1)\r
+ throw EScriptExecError("VR:X option takes exactly 1 parameter!");\r
+ \r
+- std::string opt = std::visit(VR_X(), trig.params.get()[0]);\r
++ std::string opt = std::visit(VR_X(), (*trig.params)[0]);\r
+ \r
+ boost::format fmt("%s = bit.bxor(%s, %s)");\r
+ fmt % v.str() % v.str() % opt;putLine(fmt.str());\r
+@@ -831,10 +831,10 @@ namespace ERMConverter
+ break;\r
+ case 'S': //setting variable\r
+ {\r
+- if(!trig.params.has_value() || trig.params.get().size() != 1)\r
++ if(!trig.params.has_value() || trig.params->size() != 1)\r
+ throw EScriptExecError("VR:S option takes exactly 1 parameter!");\r
+ \r
+- std::string opt = std::visit(VR_S(), trig.params.get()[0]);\r
++ std::string opt = std::visit(VR_S(), (*trig.params)[0]);\r
+ put(v.str());\r
+ put(" = ");\r
+ put(opt);\r
+@@ -849,10 +849,10 @@ namespace ERMConverter
+ break;\r
+ case 'V': //convert string to value\r
+ {\r
+- if(!trig.params.has_value() || trig.params.get().size() != 1)\r
++ if(!trig.params.has_value() || trig.params->size() != 1)\r
+ throw EScriptExecError("VR:V option takes exactly 1 parameter!");\r
+ \r
+- std::string opt = std::visit(VR_X(), trig.params.get()[0]);\r
++ std::string opt = std::visit(VR_X(), (*trig.params)[0]);\r
+ boost::format fmt("%s = tostring(%s)");\r
+ fmt % v.str() % opt;\r
+ putLine(fmt.str());\r
+@@ -877,7 +877,7 @@ namespace ERMConverter
+ {\r
+ if(body.has_value())\r
+ {\r
+- const ERM::Tbody & bo = body.get();\r
++ const ERM::Tbody & bo = *body;\r
+ for(int g=0; g<bo.size(); ++g)\r
+ {\r
+ std::visit(visitor, bo[g]);\r
+@@ -975,7 +975,7 @@ namespace ERMConverter
+ \r
+ if(body.has_value())\r
+ {\r
+- const ERM::Tbody & bo = body.get();\r
++ const ERM::Tbody & bo = *body;\r
+ if(bo.size() == 1)\r
+ {\r
+ boost::format fmt("ERM.%s(%s)");\r
+@@ -983,7 +983,7 @@ namespace ERMConverter
+ fmt % params;\r
+ \r
+ GenericReceiver gr(out, fmt.str(), (name == "DO"));\r
+- bo[0].apply_visitor(gr);\r
++ std::visit(gr,bo[0]);\r
+ }\r
+ else\r
+ {\r
+@@ -1044,7 +1044,7 @@ namespace ERMConverter
+ break;\r
+ }\r
+ \r
+- convertConditionInner(cond.rhs.get().get(), op);\r
++ convertConditionInner(cond.rhs->get(), op);\r
+ }\r
+ }\r
+ \r
+@@ -1067,7 +1067,7 @@ namespace ERMConverter
+ break;\r
+ }\r
+ \r
+- convertConditionInner(cond.rhs.get().get(), cond.ctype);\r
++ convertConditionInner(cond.rhs->get(), cond.ctype);\r
+ }\r
+ \r
+ putLine(" then ");\r
+@@ -1081,7 +1081,7 @@ namespace ERMConverter
+ if(name=="if")\r
+ {\r
+ if(condition.has_value())\r
+- convertCondition(condition.get());\r
++ convertCondition(*condition);\r
+ else\r
+ putLine("if true then");\r
+ }\r
+@@ -1097,7 +1097,7 @@ namespace ERMConverter
+ {\r
+ if(condition.has_value())\r
+ {\r
+- convertCondition(condition.get());\r
++ convertCondition(*condition);\r
+ convert(name, identifier, body);\r
+ putLine("end");\r
+ }\r
+@@ -1181,7 +1181,7 @@ namespace ERMConverter
+ {\r
+ (*out) << "{}";\r
+ }\r
+- void operator()(const VNode & opt) const;\r
++ void operator()(const boost::recursive_wrapper<VNode> & opt) const;\r
+ \r
+ void operator()(const VSymbol & opt) const \r
+ {\r
+@@ -1192,7 +1192,7 @@ namespace ERMConverter
+ TLiteralEval tmp;\r
+ (*out) << std::visit(tmp, opt);\r
+ }\r
+- void operator()(ERM const ::Tcommand & opt) const\r
++ void operator()(const ERM::Tcommand & opt) const\r
+ {\r
+ //this is how FP works, evaluation == producing side effects\r
+ //TODO: can we evaluate to smth more useful?\r
+@@ -1202,9 +1202,9 @@ namespace ERMConverter
+ }\r
+ };\r
+ \r
+- void VOptionEval::operator()(const VNode & opt) const\r
++ void VOptionEval::operator()(const boost::recursive_wrapper<VNode> & opt) const\r
+ {\r
+- VNode tmpn(opt);\r
++ VNode tmpn(opt.get());\r
+ \r
+ (*out) << "{";\r
+ \r
+@@ -1375,35 +1375,35 @@ struct ScriptScanner
+ }\r
+ void operator()(const TERMline & cmd) const\r
+ {\r
+- if(cmd.which() == 0) //TCommand\r
++ if(std::holds_alternative<Tcommand>(cmd)) //TCommand\r
+ {\r
+ Tcommand tcmd = std::get<Tcommand>(cmd);\r
+- switch (tcmd.cmd.which())\r
++ struct Visitor\r
+ {\r
+- case 0: //trigger\r
++ void operator()(const ERM::Ttrigger& t) const\r
+ {\r
+ Trigger trig;\r
+- trig.line = lp;\r
+- interpreter->triggers[ TriggerType(std::get<ERM::Ttrigger>(tcmd.cmd).name) ].push_back(trig);\r
++ trig.line = l;\r
++ i->triggers[ TriggerType(t.name) ].push_back(trig);\r
+ }\r
+- break;\r
+- case 1: //instruction\r
++ void operator()(const ERM::Tinstruction&) const\r
+ {\r
+- interpreter->instructions.push_back(lp);\r
++ i->instructions.push_back(l);\r
+ }\r
+- break;\r
+- case 3: //post trigger\r
++ void operator()(const ERM::Treceiver&) const {}\r
++ void operator()(const ERM::TPostTrigger& pt) const\r
+ {\r
+ Trigger trig;\r
+- trig.line = lp;\r
+- interpreter->postTriggers[ TriggerType(std::get<ERM::TPostTrigger>(tcmd.cmd).name) ].push_back(trig);\r
++ trig.line = l;\r
++ i->postTriggers[ TriggerType(pt.name) ].push_back(trig);\r
+ }\r
+- break;\r
+- default:\r
+- break;\r
+- }\r
+- }\r
++ const decltype(interpreter)& i;\r
++ const LinePointer& l;\r
++ };\r
+ \r
++ Visitor v{interpreter, lp};\r
++ std::visit(v, tcmd.cmd);\r
++ }\r
+ }\r
+ };\r
+ \r
+@@ -1421,68 +1421,85 @@ ERMInterpreter::~ERMInterpreter()
+ \r
+ bool ERMInterpreter::isATrigger( const ERM::TLine & line )\r
+ {\r
+- switch(line.which())\r
++ if(std::holds_alternative<ERM::TVExp>(line))\r
+ {\r
+- case 0: //v-exp\r
+- {\r
+- TVExp vexp = std::get<TVExp>(line);\r
+- if(vexp.children.empty())\r
+- return false;\r
++ TVExp vexp = std::get<TVExp>(line);\r
++ if(vexp.children.empty())\r
++ return false;\r
+ \r
+- switch (getExpType(vexp.children[0]))\r
+- {\r
+- case SYMBOL:\r
+- return false;\r
+- break;\r
+- case TCMD:\r
+- return isCMDATrigger( std::get<ERM::Tcommand>(vexp.children[0]) );\r
+- break;\r
+- default:\r
+- return false;\r
+- break;\r
+- }\r
+- }\r
+- break;\r
+- case 1: //erm\r
++ switch (getExpType(vexp.children[0]))\r
+ {\r
+- TERMline ermline = std::get<TERMline>(line);\r
+- switch(ermline.which())\r
+- {\r
+- case 0: //tcmd\r
+- return isCMDATrigger( std::get<ERM::Tcommand>(ermline) );\r
+- break;\r
+- default:\r
+- return false;\r
+- break;\r
+- }\r
++ case SYMBOL:\r
++ return false;\r
++ break;\r
++ case TCMD:\r
++ return isCMDATrigger( std::get<ERM::Tcommand>(vexp.children[0]) );\r
++ break;\r
++ default:\r
++ return false;\r
++ break;\r
+ }\r
+- break;\r
+- default:\r
+- assert(0); //it should never happen\r
+- break;\r
+ }\r
+- assert(0);\r
++ else if(std::holds_alternative<TERMline>(line))\r
++ {\r
++ TERMline ermline = std::get<TERMline>(line);\r
++ return std::holds_alternative<ERM::Tcommand>(ermline) && isCMDATrigger( std::get<ERM::Tcommand>(ermline) );\r
++ }\r
++ else\r
++ {\r
++ assert(0);\r
++ }\r
+ return false;\r
+ }\r
+ \r
+ ERM::EVOtions ERMInterpreter::getExpType(const ERM::TVOption & opt)\r
+ {\r
+- //MAINTENANCE: keep it correct!\r
+- return static_cast<ERM::EVOtions>(opt.which());\r
++ struct Visitor\r
++ {\r
++ ERM::EVOtions operator()(const boost::recursive_wrapper<ERM::TVExp>&) const\r
++ {\r
++ return ERM::EVOtions::VEXP;\r
++ }\r
++ ERM::EVOtions operator()(const ERM::TSymbol&) const\r
++ {\r
++ return ERM::EVOtions::SYMBOL;\r
++ }\r
++ ERM::EVOtions operator()(char) const\r
++ {\r
++ return ERM::EVOtions::CHAR;\r
++ }\r
++ ERM::EVOtions operator()(double) const\r
++ {\r
++ return ERM::EVOtions::DOUBLE;\r
++ }\r
++ ERM::EVOtions operator()(int) const\r
++ {\r
++ return ERM::EVOtions::INT;\r
++ }\r
++ ERM::EVOtions operator()(const ERM::Tcommand&) const\r
++ {\r
++ return ERM::EVOtions::TCMD;\r
++ }\r
++ ERM::EVOtions operator()(const ERM::TStringConstant&) const\r
++ {\r
++ return ERM::EVOtions::STRINGC;\r
++ }\r
++ };\r
++ const Visitor v;\r
++ return std::visit(v, opt);\r
+ }\r
+ \r
+ bool ERMInterpreter::isCMDATrigger(const ERM::Tcommand & cmd)\r
+ {\r
+- switch (cmd.cmd.which())\r
++ struct Visitor\r
+ {\r
+- case 0: //trigger\r
+- case 3: //post trigger\r
+- return true;\r
+- break;\r
+- default:\r
+- return false;\r
+- break;\r
+- }\r
++ bool operator()(const ERM::Ttrigger&) const { return true; }\r
++ bool operator()(const ERM::TPostTrigger&) const { return true; }\r
++ bool operator()(const ERM::Tinstruction&) const { return false; }\r
++ bool operator()(const ERM::Treceiver&) const { return false; }\r
++ };\r
++ const Visitor v;\r
++ return std::visit(v, cmd.cmd);\r
+ }\r
+ \r
+ ERM::TLine & ERMInterpreter::retrieveLine(const LinePointer & linePtr)\r
+@@ -1492,17 +1509,17 @@ ERM::TLine & ERMInterpreter::retrieveLine(const LinePointer & linePtr)
+ \r
+ ERM::TTriggerBase & ERMInterpreter::retrieveTrigger(ERM::TLine & line)\r
+ {\r
+- if(line.which() == 1)\r
++ if(std::holds_alternative<ERM::TERMline>(line))\r
+ {\r
+ ERM::TERMline &tl = std::get<ERM::TERMline>(line);\r
+- if(tl.which() == 0)\r
++ if(std::holds_alternative<ERM::Tcommand>(tl))\r
+ {\r
+ ERM::Tcommand &tcm = std::get<ERM::Tcommand>(tl);\r
+- if(tcm.cmd.which() == 0)\r
++ if(std::holds_alternative<ERM::Ttrigger>(tcm.cmd))\r
+ {\r
+ return std::get<ERM::Ttrigger>(tcm.cmd);\r
+ }\r
+- else if(tcm.cmd.which() == 3)\r
++ else if(std::holds_alternative<ERM::TPostTrigger>(tcm.cmd))\r
+ {\r
+ return std::get<ERM::TPostTrigger>(tcm.cmd);\r
+ }\r
+@@ -1569,6 +1586,40 @@ namespace VERMInterpreter
+ {\r
+ VOption convertToVOption(const ERM::TVOption & tvo)\r
+ {\r
++ struct OptionConverterVisitor\r
++ {\r
++ VOption operator()(const boost::recursive_wrapper<ERM::TVExp>& cmd) const\r
++ { \r
++ return boost::recursive_wrapper<VNode>(VNode(cmd.get()));\r
++ }\r
++ VOption operator()(const ERM::TSymbol & cmd) const\r
++ {\r
++ if(cmd.symModifier.empty())\r
++ return VSymbol(cmd.sym);\r
++ else\r
++ return boost::recursive_wrapper<VNode>(VNode(cmd));\r
++ }\r
++ VOption operator()(const char & cmd) const \r
++ {\r
++ return TLiteral(cmd);\r
++ }\r
++ VOption operator()(const double & cmd) const\r
++ {\r
++ return TLiteral(cmd);\r
++ }\r
++ VOption operator()(const int & cmd) const\r
++ {\r
++ return TLiteral(cmd);\r
++ }\r
++ VOption operator()(const ERM::Tcommand & cmd) const\r
++ {\r
++ return cmd;\r
++ }\r
++ VOption operator()(const ERM::TStringConstant & cmd) const\r
++ {\r
++ return TLiteral(cmd.str);\r
++ }\r
++ };\r
+ return std::visit(OptionConverterVisitor(), tvo);\r
+ }\r
+ \r
+@@ -1706,38 +1757,6 @@ namespace VERMInterpreter
+ return ret;\r
+ }\r
+ \r
+- VOption OptionConverterVisitor::operator()(ERM const ::TVExp & cmd) const\r
+- {\r
+- return VNode(cmd);\r
+- }\r
+- VOption OptionConverterVisitor::operator()(ERM const ::TSymbol & cmd) const\r
+- {\r
+- if(cmd.symModifier.empty())\r
+- return VSymbol(cmd.sym);\r
+- else\r
+- return VNode(cmd);\r
+- }\r
+- VOption OptionConverterVisitor::operator()(const char & cmd) const\r
+- {\r
+- return TLiteral(cmd);\r
+- }\r
+- VOption OptionConverterVisitor::operator()(const double & cmd) const\r
+- {\r
+- return TLiteral(cmd);\r
+- }\r
+- VOption OptionConverterVisitor::operator()(const int & cmd) const\r
+- {\r
+- return TLiteral(cmd);\r
+- }\r
+- VOption OptionConverterVisitor::operator()(ERM const ::Tcommand & cmd) const\r
+- {\r
+- return cmd;\r
+- }\r
+- VOption OptionConverterVisitor::operator()(ERM const ::TStringConstant & cmd) const\r
+- {\r
+- return TLiteral(cmd.str);\r
+- }\r
+-\r
+ VermTreeIterator VOptionList::cdr()\r
+ {\r
+ VermTreeIterator ret(*this);\r
+diff --git a/scripting/erm/ERMInterpreter.h b/scripting/erm/ERMInterpreter.h
+index baf3d317ee..ed25509777 100644
+--- a/scripting/erm/ERMInterpreter.h
++++ b/scripting/erm/ERMInterpreter.h
+@@ -134,7 +134,7 @@ namespace VERMInterpreter
+ "TH", "TM"\r
+ };\r
+ \r
+- for(int i=0; i<ARRAY_COUNT(validTriggers); ++i)\r
++ for(int i=0; i<std::size(validTriggers); ++i)\r
+ {\r
+ if(validTriggers[i] == trig)\r
+ return static_cast<ETrigType>(i);\r
+@@ -278,17 +278,6 @@ namespace VERMInterpreter
+ VermTreeIterator cdr();\r
+ };\r
+ \r
+- struct OptionConverterVisitor\r
+- {\r
+- VOption operator()(ERM const ::TVExp & cmd) const;\r
+- VOption operator()(ERM const ::TSymbol & cmd) const;\r
+- VOption operator()(const char & cmd) const;\r
+- VOption operator()(const double & cmd) const;\r
+- VOption operator()(const int & cmd) const;\r
+- VOption operator()(ERM const ::Tcommand & cmd) const;\r
+- VOption operator()(ERM const ::TStringConstant & cmd) const;\r
+- };\r
+-\r
+ struct VNode\r
+ {\r
+ private:\r
+diff --git a/scripting/erm/ERMParser.h b/scripting/erm/ERMParser.h
+index 29d92e61b6..95b2ccbbf3 100644
+--- a/scripting/erm/ERMParser.h
++++ b/scripting/erm/ERMParser.h
+@@ -10,6 +10,7 @@
+ #pragma once\r
+ \r
+ #include <boost/spirit/home/support/unused.hpp>\r
++#include <boost/variant/recursive_wrapper.hpp>\r
+ \r
+ namespace spirit = boost::spirit;\r
+ \r