mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-27 05:13:10 +00:00
[muparser] More functions to return errors
Return OptionalError for more functions, allowing for explicit error handling.
This commit is contained in:
parent
d97bb3425f
commit
60d9c9fa00
3 changed files with 80 additions and 63 deletions
|
@ -220,20 +220,22 @@ class ParserBase {
|
||||||
|
|
||||||
void ApplyRemainingOprt(ParserStack<token_type> &a_stOpt,
|
void ApplyRemainingOprt(ParserStack<token_type> &a_stOpt,
|
||||||
ParserStack<token_type> &a_stVal) const;
|
ParserStack<token_type> &a_stVal) const;
|
||||||
void ApplyBinOprt(ParserStack<token_type> &a_stOpt, ParserStack<token_type> &a_stVal) const;
|
OptionalError ApplyBinOprt(ParserStack<token_type> &a_stOpt,
|
||||||
|
ParserStack<token_type> &a_stVal) const;
|
||||||
|
|
||||||
void ApplyIfElse(ParserStack<token_type> &a_stOpt, ParserStack<token_type> &a_stVal) const;
|
OptionalError ApplyIfElse(ParserStack<token_type> &a_stOpt,
|
||||||
|
ParserStack<token_type> &a_stVal) const;
|
||||||
|
|
||||||
void ApplyFunc(ParserStack<token_type> &a_stOpt, ParserStack<token_type> &a_stVal,
|
OptionalError ApplyFunc(ParserStack<token_type> &a_stOpt, ParserStack<token_type> &a_stVal,
|
||||||
int iArgCount) const;
|
int iArgCount) const;
|
||||||
|
|
||||||
token_type ApplyStrFunc(const token_type &a_FunTok,
|
OptionalError ApplyStrFunc(const token_type &a_FunTok,
|
||||||
const std::vector<token_type> &a_vArg) const;
|
const std::vector<token_type> &a_vArg) const;
|
||||||
|
|
||||||
int GetOprtPrecedence(const token_type &a_Tok) const;
|
int GetOprtPrecedence(const token_type &a_Tok) const;
|
||||||
EOprtAssociativity GetOprtAssociativity(const token_type &a_Tok) const;
|
EOprtAssociativity GetOprtAssociativity(const token_type &a_Tok) const;
|
||||||
|
|
||||||
void CreateRPN() const;
|
OptionalError CreateRPN() const;
|
||||||
|
|
||||||
ValueOrError ParseString() const;
|
ValueOrError ParseString() const;
|
||||||
ValueOrError ParseCmdCode() const;
|
ValueOrError ParseCmdCode() const;
|
||||||
|
|
|
@ -291,9 +291,8 @@ class ParserToken {
|
||||||
/** \biref Get value of the token.
|
/** \biref Get value of the token.
|
||||||
|
|
||||||
Only applicable to variable and value tokens.
|
Only applicable to variable and value tokens.
|
||||||
\throw exception_type if token is no value/variable token.
|
|
||||||
*/
|
*/
|
||||||
TBase GetVal() const {
|
ValueOrError GetVal() const {
|
||||||
switch (m_iCode) {
|
switch (m_iCode) {
|
||||||
case cmVAL:
|
case cmVAL:
|
||||||
return m_fVal;
|
return m_fVal;
|
||||||
|
|
|
@ -538,9 +538,9 @@ EOprtAssociativity ParserBase::GetOprtAssociativity(const token_type &a_Tok) con
|
||||||
const varmap_type &ParserBase::GetUsedVar() const {
|
const varmap_type &ParserBase::GetUsedVar() const {
|
||||||
try {
|
try {
|
||||||
m_pTokenReader->IgnoreUndefVar(true);
|
m_pTokenReader->IgnoreUndefVar(true);
|
||||||
CreateRPN(); // try to create bytecode, but don't use it for any further calculations since
|
// Try to create bytecode, but don't use it for any further calculations since it may
|
||||||
// it
|
// contain references to nonexisting variables.
|
||||||
// may contain references to nonexisting variables.
|
OptionalError err = CreateRPN();
|
||||||
m_pParseFormula = &ParserBase::ParseString;
|
m_pParseFormula = &ParserBase::ParseString;
|
||||||
m_pTokenReader->IgnoreUndefVar(false);
|
m_pTokenReader->IgnoreUndefVar(false);
|
||||||
} catch (exception_type & /*e*/) {
|
} catch (exception_type & /*e*/) {
|
||||||
|
@ -583,45 +583,42 @@ const string_type &ParserBase::GetExpr() const { return m_pTokenReader->GetExpr(
|
||||||
\param a_FunTok Function token.
|
\param a_FunTok Function token.
|
||||||
\throw exception_type If the function token is not a string function
|
\throw exception_type If the function token is not a string function
|
||||||
*/
|
*/
|
||||||
ParserBase::token_type ParserBase::ApplyStrFunc(const token_type &a_FunTok,
|
OptionalError ParserBase::ApplyStrFunc(const token_type &a_FunTok,
|
||||||
const std::vector<token_type> &a_vArg) const {
|
const std::vector<token_type> &a_vArg) const {
|
||||||
if (a_vArg.back().GetCode() != cmSTRING)
|
if (a_vArg.back().GetCode() != cmSTRING)
|
||||||
Error(ecSTRING_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString());
|
Error(ecSTRING_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString());
|
||||||
|
|
||||||
token_type valTok;
|
token_type valTok;
|
||||||
generic_fun_type pFunc = a_FunTok.GetFuncAddr();
|
generic_fun_type pFunc = a_FunTok.GetFuncAddr();
|
||||||
assert(pFunc);
|
assert(pFunc);
|
||||||
|
bool errored = false;
|
||||||
try {
|
// Check function arguments; write dummy value into valtok to represent the result
|
||||||
// Check function arguments; write dummy value into valtok to represent the result
|
switch (a_FunTok.GetArgCount()) {
|
||||||
switch (a_FunTok.GetArgCount()) {
|
case 0:
|
||||||
case 0:
|
valTok.SetVal(1);
|
||||||
valTok.SetVal(1);
|
a_vArg[0].GetAsString();
|
||||||
a_vArg[0].GetAsString();
|
break;
|
||||||
break;
|
case 1:
|
||||||
case 1:
|
valTok.SetVal(1);
|
||||||
valTok.SetVal(1);
|
a_vArg[1].GetAsString();
|
||||||
a_vArg[1].GetAsString();
|
errored |= a_vArg[0].GetVal().has_error();
|
||||||
a_vArg[0].GetVal();
|
break;
|
||||||
break;
|
case 2:
|
||||||
case 2:
|
valTok.SetVal(1);
|
||||||
valTok.SetVal(1);
|
a_vArg[2].GetAsString();
|
||||||
a_vArg[2].GetAsString();
|
errored |= a_vArg[1].GetVal().has_error();
|
||||||
a_vArg[1].GetVal();
|
errored |= a_vArg[0].GetVal().has_error();
|
||||||
a_vArg[0].GetVal();
|
break;
|
||||||
break;
|
default:
|
||||||
default:
|
assert(0 && "Unexpected arg count");
|
||||||
assert(0 && "Unexpected arg count");
|
}
|
||||||
}
|
if (errored) {
|
||||||
} catch (ParserError &) {
|
|
||||||
Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString());
|
Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
// string functions won't be optimized
|
// string functions won't be optimized
|
||||||
m_vRPN.AddStrFun(pFunc, a_FunTok.GetArgCount(), a_vArg.back().GetIdx());
|
m_vRPN.AddStrFun(pFunc, a_FunTok.GetArgCount(), a_vArg.back().GetIdx());
|
||||||
|
return {};
|
||||||
// Push dummy value representing the function result to the stack
|
|
||||||
return valTok;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
@ -629,14 +626,14 @@ ParserBase::token_type ParserBase::ApplyStrFunc(const token_type &a_FunTok,
|
||||||
\param iArgCount Number of Arguments actually gathered used only for multiarg functions.
|
\param iArgCount Number of Arguments actually gathered used only for multiarg functions.
|
||||||
\post The result is pushed to the value stack
|
\post The result is pushed to the value stack
|
||||||
\post The function token is removed from the stack
|
\post The function token is removed from the stack
|
||||||
\throw exception_type if Argument count does not match function requirements.
|
\return ParserError if Argument count does not match function requirements.
|
||||||
*/
|
*/
|
||||||
void ParserBase::ApplyFunc(ParserStack<token_type> &a_stOpt, ParserStack<token_type> &a_stVal,
|
OptionalError ParserBase::ApplyFunc(ParserStack<token_type> &a_stOpt,
|
||||||
int a_iArgCount) const {
|
ParserStack<token_type> &a_stVal, int a_iArgCount) const {
|
||||||
assert(m_pTokenReader.get());
|
assert(m_pTokenReader.get());
|
||||||
|
|
||||||
// Operator stack empty or does not contain tokens with callback functions
|
// Operator stack empty or does not contain tokens with callback functions
|
||||||
if (a_stOpt.empty() || a_stOpt.top().GetFuncAddr() == 0) return;
|
if (a_stOpt.empty() || a_stOpt.top().GetFuncAddr() == 0) return {};
|
||||||
|
|
||||||
token_type funTok = a_stOpt.pop();
|
token_type funTok = a_stOpt.pop();
|
||||||
assert(funTok.GetFuncAddr());
|
assert(funTok.GetFuncAddr());
|
||||||
|
@ -675,14 +672,16 @@ void ParserBase::ApplyFunc(ParserStack<token_type> &a_stOpt, ParserStack<token_t
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (funTok.GetCode()) {
|
switch (funTok.GetCode()) {
|
||||||
case cmFUNC_STR:
|
case cmFUNC_STR: {
|
||||||
stArg.push_back(a_stVal.pop());
|
stArg.push_back(a_stVal.pop());
|
||||||
|
|
||||||
if (stArg.back().GetType() == tpSTR && funTok.GetType() != tpSTR)
|
if (stArg.back().GetType() == tpSTR && funTok.GetType() != tpSTR)
|
||||||
Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString());
|
Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString());
|
||||||
|
|
||||||
ApplyStrFunc(funTok, stArg);
|
OptionalError err = ApplyStrFunc(funTok, stArg);
|
||||||
|
if (err.has_error()) return err;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case cmOPRT_BIN:
|
case cmOPRT_BIN:
|
||||||
case cmOPRT_POSTFIX:
|
case cmOPRT_POSTFIX:
|
||||||
|
@ -703,11 +702,12 @@ void ParserBase::ApplyFunc(ParserStack<token_type> &a_stOpt, ParserStack<token_t
|
||||||
token_type token;
|
token_type token;
|
||||||
token.SetVal(1);
|
token.SetVal(1);
|
||||||
a_stVal.push(token);
|
a_stVal.push(token);
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
void ParserBase::ApplyIfElse(ParserStack<token_type> &a_stOpt,
|
OptionalError ParserBase::ApplyIfElse(ParserStack<token_type> &a_stOpt,
|
||||||
ParserStack<token_type> &a_stVal) const {
|
ParserStack<token_type> &a_stVal) const {
|
||||||
// Check if there is an if Else clause to be calculated
|
// Check if there is an if Else clause to be calculated
|
||||||
while (a_stOpt.size() && a_stOpt.top().GetCode() == cmELSE) {
|
while (a_stOpt.size() && a_stOpt.top().GetCode() == cmELSE) {
|
||||||
token_type opElse = a_stOpt.pop();
|
token_type opElse = a_stOpt.pop();
|
||||||
|
@ -724,7 +724,9 @@ void ParserBase::ApplyIfElse(ParserStack<token_type> &a_stOpt,
|
||||||
token_type vVal1 = a_stVal.pop();
|
token_type vVal1 = a_stVal.pop();
|
||||||
token_type vExpr = a_stVal.pop();
|
token_type vExpr = a_stVal.pop();
|
||||||
|
|
||||||
a_stVal.push((vExpr.GetVal() != 0) ? vVal1 : vVal2);
|
ValueOrError vExprValue = vExpr.GetVal();
|
||||||
|
if (vExprValue.has_error()) return vExprValue.error();
|
||||||
|
a_stVal.push((vExprValue.value() != 0) ? vVal1 : vVal2);
|
||||||
|
|
||||||
token_type opIf = a_stOpt.pop();
|
token_type opIf = a_stOpt.pop();
|
||||||
assert(opElse.GetCode() == cmELSE && "Invalid if/else clause");
|
assert(opElse.GetCode() == cmELSE && "Invalid if/else clause");
|
||||||
|
@ -732,17 +734,18 @@ void ParserBase::ApplyIfElse(ParserStack<token_type> &a_stOpt,
|
||||||
|
|
||||||
m_vRPN.AddIfElse(cmENDIF);
|
m_vRPN.AddIfElse(cmENDIF);
|
||||||
} // while pending if-else-clause found
|
} // while pending if-else-clause found
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
/** \brief Performs the necessary steps to write code for
|
/** \brief Performs the necessary steps to write code for
|
||||||
the execution of binary operators into the bytecode.
|
the execution of binary operators into the bytecode.
|
||||||
*/
|
*/
|
||||||
void ParserBase::ApplyBinOprt(ParserStack<token_type> &a_stOpt,
|
OptionalError ParserBase::ApplyBinOprt(ParserStack<token_type> &a_stOpt,
|
||||||
ParserStack<token_type> &a_stVal) const {
|
ParserStack<token_type> &a_stVal) const {
|
||||||
// is it a user defined binary operator?
|
// is it a user defined binary operator?
|
||||||
if (a_stOpt.top().GetCode() == cmOPRT_BIN) {
|
if (a_stOpt.top().GetCode() == cmOPRT_BIN) {
|
||||||
ApplyFunc(a_stOpt, a_stVal, 2);
|
return ApplyFunc(a_stOpt, a_stVal, 2);
|
||||||
} else {
|
} else {
|
||||||
assert(a_stVal.size() >= 2 && "Too few arguments for binary operator");
|
assert(a_stVal.size() >= 2 && "Too few arguments for binary operator");
|
||||||
token_type valTok1 = a_stVal.pop(), valTok2 = a_stVal.pop(), optTok = a_stOpt.pop(), resTok;
|
token_type valTok1 = a_stVal.pop(), valTok2 = a_stVal.pop(), optTok = a_stOpt.pop(), resTok;
|
||||||
|
@ -761,6 +764,7 @@ void ParserBase::ApplyBinOprt(ParserStack<token_type> &a_stOpt,
|
||||||
resTok.SetVal(1);
|
resTok.SetVal(1);
|
||||||
a_stVal.push(resTok);
|
a_stVal.push(resTok);
|
||||||
}
|
}
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
@ -1029,8 +1033,8 @@ ValueOrError ParserBase::ParseCmdCode() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
void ParserBase::CreateRPN() const {
|
OptionalError ParserBase::CreateRPN() const {
|
||||||
if (!m_pTokenReader->GetExpr().length()) Error(ecUNEXPECTED_EOF, 0);
|
if (!m_pTokenReader->GetExpr().length()) return ParserError(ecUNEXPECTED_EOF, 0);
|
||||||
|
|
||||||
ParserStack<token_type> stOpt, stVal;
|
ParserStack<token_type> stOpt, stVal;
|
||||||
ParserStack<int> stArgCount;
|
ParserStack<int> stArgCount;
|
||||||
|
@ -1061,10 +1065,13 @@ void ParserBase::CreateRPN() const {
|
||||||
m_vRPN.AddVar(static_cast<value_type *>(opt.GetVar()));
|
m_vRPN.AddVar(static_cast<value_type *>(opt.GetVar()));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case cmVAL:
|
case cmVAL: {
|
||||||
stVal.push(opt);
|
stVal.push(opt);
|
||||||
m_vRPN.AddVal(opt.GetVal());
|
ValueOrError optVal = opt.GetVal();
|
||||||
|
if (optVal.has_error()) throw optVal.error();
|
||||||
|
m_vRPN.AddVal(optVal.value());
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case cmELSE:
|
case cmELSE:
|
||||||
m_nIfElseCounter--;
|
m_nIfElseCounter--;
|
||||||
|
@ -1117,7 +1124,8 @@ void ParserBase::CreateRPN() const {
|
||||||
// was a function before this bracket
|
// was a function before this bracket
|
||||||
if (stOpt.size() && stOpt.top().GetCode() != cmOPRT_INFIX &&
|
if (stOpt.size() && stOpt.top().GetCode() != cmOPRT_INFIX &&
|
||||||
stOpt.top().GetCode() != cmOPRT_BIN && stOpt.top().GetFuncAddr() != 0) {
|
stOpt.top().GetCode() != cmOPRT_BIN && stOpt.top().GetFuncAddr() != 0) {
|
||||||
ApplyFunc(stOpt, stVal, iArgCount);
|
OptionalError err = ApplyFunc(stOpt, stVal, iArgCount);
|
||||||
|
if (err.has_error()) return err.error();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // if bracket content is evaluated
|
} // if bracket content is evaluated
|
||||||
|
@ -1166,10 +1174,14 @@ void ParserBase::CreateRPN() const {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OptionalError oerr;
|
||||||
if (stOpt.top().GetCode() == cmOPRT_INFIX)
|
if (stOpt.top().GetCode() == cmOPRT_INFIX)
|
||||||
ApplyFunc(stOpt, stVal, 1);
|
oerr = ApplyFunc(stOpt, stVal, 1);
|
||||||
else
|
else
|
||||||
ApplyBinOprt(stOpt, stVal);
|
oerr = ApplyBinOprt(stOpt, stVal);
|
||||||
|
if (oerr.has_error()) {
|
||||||
|
return oerr.error();
|
||||||
|
}
|
||||||
} // while ( ... )
|
} // while ( ... )
|
||||||
|
|
||||||
if (opt.GetCode() == cmIF) m_vRPN.AddIfElse(opt.GetCode());
|
if (opt.GetCode() == cmIF) m_vRPN.AddIfElse(opt.GetCode());
|
||||||
|
@ -1192,10 +1204,12 @@ void ParserBase::CreateRPN() const {
|
||||||
stOpt.push(opt);
|
stOpt.push(opt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case cmOPRT_POSTFIX:
|
case cmOPRT_POSTFIX: {
|
||||||
stOpt.push(opt);
|
stOpt.push(opt);
|
||||||
ApplyFunc(stOpt, stVal, 1); // this is the postfix operator
|
OptionalError oerr = ApplyFunc(stOpt, stVal, 1); // this is the postfix operator
|
||||||
|
if (oerr.has_error()) return oerr.error();
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(0 && "muParser internal error");
|
assert(0 && "muParser internal error");
|
||||||
|
@ -1228,6 +1242,7 @@ void ParserBase::CreateRPN() const {
|
||||||
if (stVal.top().GetType() != tpDBL) Error(ecSTR_RESULT);
|
if (stVal.top().GetType() != tpDBL) Error(ecSTR_RESULT);
|
||||||
|
|
||||||
m_vStackBuffer.resize(m_vRPN.GetMaxStackSize() * s_MaxNumOpenMPThreads);
|
m_vStackBuffer.resize(m_vRPN.GetMaxStackSize() * s_MaxNumOpenMPThreads);
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
@ -1241,7 +1256,8 @@ void ParserBase::CreateRPN() const {
|
||||||
*/
|
*/
|
||||||
ValueOrError ParserBase::ParseString() const {
|
ValueOrError ParserBase::ParseString() const {
|
||||||
try {
|
try {
|
||||||
CreateRPN();
|
OptionalError oerr = CreateRPN();
|
||||||
|
if (oerr.has_error()) return oerr.error();
|
||||||
m_pParseFormula = &ParserBase::ParseCmdCode;
|
m_pParseFormula = &ParserBase::ParseCmdCode;
|
||||||
return (this->*m_pParseFormula)();
|
return (this->*m_pParseFormula)();
|
||||||
} catch (ParserError &exc) {
|
} catch (ParserError &exc) {
|
||||||
|
@ -1394,7 +1410,7 @@ void ParserBase::StackDump(const ParserStack<token_type> &a_stVal,
|
||||||
if (val.GetType() == tpSTR)
|
if (val.GetType() == tpSTR)
|
||||||
mu::console() << _T(" \"") << val.GetAsString() << _T("\" ");
|
mu::console() << _T(" \"") << val.GetAsString() << _T("\" ");
|
||||||
else
|
else
|
||||||
mu::console() << _T(" ") << val.GetVal() << _T(" ");
|
mu::console() << _T(" ") << val.GetVal().value() << _T(" ");
|
||||||
}
|
}
|
||||||
mu::console() << "\nOperator stack:\n";
|
mu::console() << "\nOperator stack:\n";
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue