1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-08 00:39:47 +02:00

Merge pull request #2950 from soulsource/feature/make-erm-compile-again

Make ERM compile again.
This commit is contained in:
Ivan Savenko 2023-09-27 15:42:33 +03:00 committed by GitHub
commit 724eb7902e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 151 additions and 142 deletions

View File

@ -163,7 +163,7 @@ namespace ERMConverter
Variable operator()(const TVarExpNotMacro & val) const
{
if(val.val.has_value())
return Variable(val.varsym, val.val.get());
return Variable(val.varsym, *val.val);
else
return Variable(val.varsym, 0);
}
@ -392,7 +392,7 @@ namespace ERMConverter
if(trig.params.has_value())
{
for(auto & p : trig.params.get())
for(auto & p : *trig.params)
optionParams.push_back(std::visit(BodyOption(), p));
}
@ -572,7 +572,7 @@ namespace ERMConverter
{
if(option.params.has_value())
{
for(auto & p : option.params.get())
for(auto & p : *option.params)
{
std::string macroName = std::visit(MC_S(), p);
@ -739,7 +739,7 @@ namespace ERMConverter
if(trig.params.has_value())
{
for(auto & p : trig.params.get())
for(auto & p : *trig.params)
optionParams.push_back(std::visit(BodyOption(), p));
}
@ -759,10 +759,10 @@ namespace ERMConverter
break;
case 'H': //checking if string is empty
{
if(!trig.params.has_value() || trig.params.get().size() != 1)
if(!trig.params.has_value() || trig.params->size() != 1)
throw EScriptExecError("VR:H option takes exactly 1 parameter!");
std::string opt = std::visit(VR_H(), trig.params.get()[0]);
std::string opt = std::visit(VR_H(), (*trig.params)[0]);
boost::format fmt("ERM.VR(%s):H(%s)");
fmt % v.str() % opt;
putLine(fmt.str());
@ -770,10 +770,10 @@ namespace ERMConverter
break;
case 'U':
{
if(!trig.params.has_value() || trig.params.get().size() != 1)
if(!trig.params.has_value() || trig.params->size() != 1)
throw EScriptExecError("VR:H/U need 1 parameter!");
std::string opt = std::visit(VR_S(), trig.params.get()[0]);
std::string opt = std::visit(VR_S(), (*trig.params)[0]);
boost::format fmt("ERM.VR(%s):%c(%s)");
fmt % v.str() % (trig.optionCode) % opt;
putLine(fmt.str());
@ -781,10 +781,10 @@ namespace ERMConverter
break;
case 'M': //string operations
{
if(!trig.params.has_value() || trig.params.get().size() < 2)
if(!trig.params.has_value() || trig.params->size() < 2)
throw EScriptExecError("VR:M needs at least 2 parameters!");
std::string opt = std::visit(VR_X(), trig.params.get()[0]);
std::string opt = std::visit(VR_X(), (*trig.params)[0]);
int paramIndex = 1;
if(opt == "3")
@ -795,16 +795,16 @@ namespace ERMConverter
}
else
{
auto target = std::visit(VR_X(), trig.params.get()[paramIndex++]);
auto target = std::visit(VR_X(), (*trig.params)[paramIndex++]);
boost::format fmt("%s = ERM.VR(%s):M%s(");
fmt % target % v.str() % opt;
put(fmt.str());
}
for(int i = paramIndex; i < trig.params.get().size(); i++)
for(int i = paramIndex; i < trig.params->size(); i++)
{
opt = std::visit(VR_X(), trig.params.get()[i]);
opt = std::visit(VR_X(), (*trig.params)[i]);
if(i > paramIndex) put(",");
put(opt);
}
@ -814,10 +814,10 @@ namespace ERMConverter
break;
case 'X': //bit xor
{
if(!trig.params.has_value() || trig.params.get().size() != 1)
if(!trig.params.has_value() || trig.params->size() != 1)
throw EScriptExecError("VR:X option takes exactly 1 parameter!");
std::string opt = std::visit(VR_X(), trig.params.get()[0]);
std::string opt = std::visit(VR_X(), (*trig.params)[0]);
boost::format fmt("%s = bit.bxor(%s, %s)");
fmt % v.str() % v.str() % opt;putLine(fmt.str());
@ -831,10 +831,10 @@ namespace ERMConverter
break;
case 'S': //setting variable
{
if(!trig.params.has_value() || trig.params.get().size() != 1)
if(!trig.params.has_value() || trig.params->size() != 1)
throw EScriptExecError("VR:S option takes exactly 1 parameter!");
std::string opt = std::visit(VR_S(), trig.params.get()[0]);
std::string opt = std::visit(VR_S(), (*trig.params)[0]);
put(v.str());
put(" = ");
put(opt);
@ -849,10 +849,10 @@ namespace ERMConverter
break;
case 'V': //convert string to value
{
if(!trig.params.has_value() || trig.params.get().size() != 1)
if(!trig.params.has_value() || trig.params->size() != 1)
throw EScriptExecError("VR:V option takes exactly 1 parameter!");
std::string opt = std::visit(VR_X(), trig.params.get()[0]);
std::string opt = std::visit(VR_X(), (*trig.params)[0]);
boost::format fmt("%s = tostring(%s)");
fmt % v.str() % opt;
putLine(fmt.str());
@ -877,7 +877,7 @@ namespace ERMConverter
{
if(body.has_value())
{
const ERM::Tbody & bo = body.get();
const ERM::Tbody & bo = *body;
for(int g=0; g<bo.size(); ++g)
{
std::visit(visitor, bo[g]);
@ -975,7 +975,7 @@ namespace ERMConverter
if(body.has_value())
{
const ERM::Tbody & bo = body.get();
const ERM::Tbody & bo = *body;
if(bo.size() == 1)
{
boost::format fmt("ERM.%s(%s)");
@ -983,7 +983,7 @@ namespace ERMConverter
fmt % params;
GenericReceiver gr(out, fmt.str(), (name == "DO"));
bo[0].apply_visitor(gr);
std::visit(gr,bo[0]);
}
else
{
@ -1044,7 +1044,7 @@ namespace ERMConverter
break;
}
convertConditionInner(cond.rhs.get().get(), op);
convertConditionInner(cond.rhs->get(), op);
}
}
@ -1067,7 +1067,7 @@ namespace ERMConverter
break;
}
convertConditionInner(cond.rhs.get().get(), cond.ctype);
convertConditionInner(cond.rhs->get(), cond.ctype);
}
putLine(" then ");
@ -1081,7 +1081,7 @@ namespace ERMConverter
if(name=="if")
{
if(condition.has_value())
convertCondition(condition.get());
convertCondition(*condition);
else
putLine("if true then");
}
@ -1097,7 +1097,7 @@ namespace ERMConverter
{
if(condition.has_value())
{
convertCondition(condition.get());
convertCondition(*condition);
convert(name, identifier, body);
putLine("end");
}
@ -1181,7 +1181,7 @@ namespace ERMConverter
{
(*out) << "{}";
}
void operator()(const VNode & opt) const;
void operator()(const boost::recursive_wrapper<VNode> & opt) const;
void operator()(const VSymbol & opt) const
{
@ -1192,7 +1192,7 @@ namespace ERMConverter
TLiteralEval tmp;
(*out) << std::visit(tmp, opt);
}
void operator()(ERM const ::Tcommand & opt) const
void operator()(const ERM::Tcommand & opt) const
{
//this is how FP works, evaluation == producing side effects
//TODO: can we evaluate to smth more useful?
@ -1202,9 +1202,9 @@ namespace ERMConverter
}
};
void VOptionEval::operator()(const VNode & opt) const
void VOptionEval::operator()(const boost::recursive_wrapper<VNode> & opt) const
{
VNode tmpn(opt);
VNode tmpn(opt.get());
(*out) << "{";
@ -1375,35 +1375,35 @@ struct ScriptScanner
}
void operator()(const TERMline & cmd) const
{
if(cmd.which() == 0) //TCommand
if(std::holds_alternative<Tcommand>(cmd)) //TCommand
{
Tcommand tcmd = std::get<Tcommand>(cmd);
switch (tcmd.cmd.which())
struct Visitor
{
case 0: //trigger
void operator()(const ERM::Ttrigger& t) const
{
Trigger trig;
trig.line = lp;
interpreter->triggers[ TriggerType(std::get<ERM::Ttrigger>(tcmd.cmd).name) ].push_back(trig);
trig.line = l;
i->triggers[ TriggerType(t.name) ].push_back(trig);
}
break;
case 1: //instruction
void operator()(const ERM::Tinstruction&) const
{
interpreter->instructions.push_back(lp);
i->instructions.push_back(l);
}
break;
case 3: //post trigger
void operator()(const ERM::Treceiver&) const {}
void operator()(const ERM::TPostTrigger& pt) const
{
Trigger trig;
trig.line = lp;
interpreter->postTriggers[ TriggerType(std::get<ERM::TPostTrigger>(tcmd.cmd).name) ].push_back(trig);
trig.line = l;
i->postTriggers[ TriggerType(pt.name) ].push_back(trig);
}
break;
default:
break;
}
}
const decltype(interpreter)& i;
const LinePointer& l;
};
Visitor v{interpreter, lp};
std::visit(v, tcmd.cmd);
}
}
};
@ -1421,68 +1421,85 @@ ERMInterpreter::~ERMInterpreter()
bool ERMInterpreter::isATrigger( const ERM::TLine & line )
{
switch(line.which())
if(std::holds_alternative<ERM::TVExp>(line))
{
case 0: //v-exp
{
TVExp vexp = std::get<TVExp>(line);
if(vexp.children.empty())
return false;
TVExp vexp = std::get<TVExp>(line);
if(vexp.children.empty())
return false;
switch (getExpType(vexp.children[0]))
{
case SYMBOL:
return false;
break;
case TCMD:
return isCMDATrigger( std::get<ERM::Tcommand>(vexp.children[0]) );
break;
default:
return false;
break;
}
}
break;
case 1: //erm
switch (getExpType(vexp.children[0]))
{
TERMline ermline = std::get<TERMline>(line);
switch(ermline.which())
{
case 0: //tcmd
return isCMDATrigger( std::get<ERM::Tcommand>(ermline) );
break;
default:
return false;
break;
}
case SYMBOL:
return false;
break;
case TCMD:
return isCMDATrigger( std::get<ERM::Tcommand>(vexp.children[0]) );
break;
default:
return false;
break;
}
break;
default:
assert(0); //it should never happen
break;
}
assert(0);
else if(std::holds_alternative<TERMline>(line))
{
TERMline ermline = std::get<TERMline>(line);
return std::holds_alternative<ERM::Tcommand>(ermline) && isCMDATrigger( std::get<ERM::Tcommand>(ermline) );
}
else
{
assert(0);
}
return false;
}
ERM::EVOtions ERMInterpreter::getExpType(const ERM::TVOption & opt)
{
//MAINTENANCE: keep it correct!
return static_cast<ERM::EVOtions>(opt.which());
struct Visitor
{
ERM::EVOtions operator()(const boost::recursive_wrapper<ERM::TVExp>&) const
{
return ERM::EVOtions::VEXP;
}
ERM::EVOtions operator()(const ERM::TSymbol&) const
{
return ERM::EVOtions::SYMBOL;
}
ERM::EVOtions operator()(char) const
{
return ERM::EVOtions::CHAR;
}
ERM::EVOtions operator()(double) const
{
return ERM::EVOtions::DOUBLE;
}
ERM::EVOtions operator()(int) const
{
return ERM::EVOtions::INT;
}
ERM::EVOtions operator()(const ERM::Tcommand&) const
{
return ERM::EVOtions::TCMD;
}
ERM::EVOtions operator()(const ERM::TStringConstant&) const
{
return ERM::EVOtions::STRINGC;
}
};
const Visitor v;
return std::visit(v, opt);
}
bool ERMInterpreter::isCMDATrigger(const ERM::Tcommand & cmd)
{
switch (cmd.cmd.which())
struct Visitor
{
case 0: //trigger
case 3: //post trigger
return true;
break;
default:
return false;
break;
}
bool operator()(const ERM::Ttrigger&) const { return true; }
bool operator()(const ERM::TPostTrigger&) const { return true; }
bool operator()(const ERM::Tinstruction&) const { return false; }
bool operator()(const ERM::Treceiver&) const { return false; }
};
const Visitor v;
return std::visit(v, cmd.cmd);
}
ERM::TLine & ERMInterpreter::retrieveLine(const LinePointer & linePtr)
@ -1492,17 +1509,17 @@ ERM::TLine & ERMInterpreter::retrieveLine(const LinePointer & linePtr)
ERM::TTriggerBase & ERMInterpreter::retrieveTrigger(ERM::TLine & line)
{
if(line.which() == 1)
if(std::holds_alternative<ERM::TERMline>(line))
{
ERM::TERMline &tl = std::get<ERM::TERMline>(line);
if(tl.which() == 0)
if(std::holds_alternative<ERM::Tcommand>(tl))
{
ERM::Tcommand &tcm = std::get<ERM::Tcommand>(tl);
if(tcm.cmd.which() == 0)
if(std::holds_alternative<ERM::Ttrigger>(tcm.cmd))
{
return std::get<ERM::Ttrigger>(tcm.cmd);
}
else if(tcm.cmd.which() == 3)
else if(std::holds_alternative<ERM::TPostTrigger>(tcm.cmd))
{
return std::get<ERM::TPostTrigger>(tcm.cmd);
}
@ -1569,6 +1586,40 @@ namespace VERMInterpreter
{
VOption convertToVOption(const ERM::TVOption & tvo)
{
struct OptionConverterVisitor
{
VOption operator()(const boost::recursive_wrapper<ERM::TVExp>& cmd) const
{
return boost::recursive_wrapper<VNode>(VNode(cmd.get()));
}
VOption operator()(const ERM::TSymbol & cmd) const
{
if(cmd.symModifier.empty())
return VSymbol(cmd.sym);
else
return boost::recursive_wrapper<VNode>(VNode(cmd));
}
VOption operator()(const char & cmd) const
{
return TLiteral(cmd);
}
VOption operator()(const double & cmd) const
{
return TLiteral(cmd);
}
VOption operator()(const int & cmd) const
{
return TLiteral(cmd);
}
VOption operator()(const ERM::Tcommand & cmd) const
{
return cmd;
}
VOption operator()(const ERM::TStringConstant & cmd) const
{
return TLiteral(cmd.str);
}
};
return std::visit(OptionConverterVisitor(), tvo);
}
@ -1706,38 +1757,6 @@ namespace VERMInterpreter
return ret;
}
VOption OptionConverterVisitor::operator()(ERM const ::TVExp & cmd) const
{
return VNode(cmd);
}
VOption OptionConverterVisitor::operator()(ERM const ::TSymbol & cmd) const
{
if(cmd.symModifier.empty())
return VSymbol(cmd.sym);
else
return VNode(cmd);
}
VOption OptionConverterVisitor::operator()(const char & cmd) const
{
return TLiteral(cmd);
}
VOption OptionConverterVisitor::operator()(const double & cmd) const
{
return TLiteral(cmd);
}
VOption OptionConverterVisitor::operator()(const int & cmd) const
{
return TLiteral(cmd);
}
VOption OptionConverterVisitor::operator()(ERM const ::Tcommand & cmd) const
{
return cmd;
}
VOption OptionConverterVisitor::operator()(ERM const ::TStringConstant & cmd) const
{
return TLiteral(cmd.str);
}
VermTreeIterator VOptionList::cdr()
{
VermTreeIterator ret(*this);

View File

@ -134,7 +134,7 @@ namespace VERMInterpreter
"TH", "TM"
};
for(int i=0; i<ARRAY_COUNT(validTriggers); ++i)
for(int i=0; i<std::size(validTriggers); ++i)
{
if(validTriggers[i] == trig)
return static_cast<ETrigType>(i);
@ -278,17 +278,6 @@ namespace VERMInterpreter
VermTreeIterator cdr();
};
struct OptionConverterVisitor
{
VOption operator()(ERM const ::TVExp & cmd) const;
VOption operator()(ERM const ::TSymbol & cmd) const;
VOption operator()(const char & cmd) const;
VOption operator()(const double & cmd) const;
VOption operator()(const int & cmd) const;
VOption operator()(ERM const ::Tcommand & cmd) const;
VOption operator()(ERM const ::TStringConstant & cmd) const;
};
struct VNode
{
private:

View File

@ -10,6 +10,7 @@
#pragma once
#include <boost/spirit/home/support/unused.hpp>
#include <boost/variant/recursive_wrapper.hpp>
namespace spirit = boost::spirit;