upd: include exception info in return value

This commit is contained in:
2023-11-10 08:43:57 +08:00
parent fb9acd28bf
commit 169969dc8a
5 changed files with 103 additions and 91 deletions

View File

@ -14,24 +14,30 @@
class InterpretException : public std::exception {
public:
InterpretException() {}
InterpretException(const char *message) : m_message(message) {}
InterpretException(const char *__message, int __code)
: message(__message), code(__code) {}
const char *what() const noexcept override { return m_message; }
const char *what() const noexcept override { return message.c_str(); }
const int GetCode() const noexcept { return code; }
~InterpretException() noexcept override {}
private:
const char *m_message;
std::string message;
int code;
};
class FatalError : public std::exception {
public:
FatalError(const char *message) : m_message(message) {}
FatalError(const char *__message, int __code)
: message(__message), code(__code) {}
const char *what() const noexcept override { return m_message; }
const char *what() const noexcept override { return message.c_str(); }
const int GetCode() const noexcept { return code; }
private:
const char *m_message;
std::string message;
int code;
};
enum FlowControlStatusType { BREAK, CONTINUE, RETURN };
struct FlowType {

View File

@ -80,7 +80,8 @@ std::any EvalVisitor::visitExpr_stmt(Python3Parser::Expr_stmtContext *ctx) {
if (!ptr_var && !ptr_vec)
throw InterpretException(
"visitExpr_stmt: Expect left value or tuple at the left of "
"augassign");
"augassign",
1);
if (ptr_var) {
std::any old_val = DeQuate(*ptr_var, Variables);
if (ctx->augassign()->ADD_ASSIGN())
@ -96,17 +97,17 @@ std::any EvalVisitor::visitExpr_stmt(Python3Parser::Expr_stmtContext *ctx) {
else if (ctx->augassign()->MOD_ASSIGN())
SelfMod(old_val, right_value);
else
throw FatalError("visitExpr_stmt: Unknown operator at augassign");
throw FatalError("visitExpr_stmt: Unknown operator at augassign", 2);
Variables.WriteVariable(ptr_var->name, old_val);
} else {
if (ptr_vec->size() !=
std::any_cast<std::vector<std::any>>(right_value).size())
throw InterpretException("visitExpr_stmt: Tuple size not match");
throw InterpretException("visitExpr_stmt: Tuple size not match", 3);
for (int i = 0; i < ptr_vec->size(); i++) {
ptr_var = std::any_cast<RawVarible>(&(*ptr_vec)[i]);
if (!ptr_var)
throw InterpretException(
"visitExpr_stmt: Expect left value at the left of augassign");
"visitExpr_stmt: Expect left value at the left of augassign", 4);
std::any old_val = DeQuate(*ptr_var, Variables);
if (ctx->augassign()->ADD_ASSIGN())
SelfAdd(old_val,
@ -127,7 +128,7 @@ std::any EvalVisitor::visitExpr_stmt(Python3Parser::Expr_stmtContext *ctx) {
SelfMod(old_val,
std::any_cast<std::vector<std::any>>(right_value)[i]);
else
throw FatalError("visitExpr_stmt: Unknown operator at augassign");
throw FatalError("visitExpr_stmt: Unknown operator at augassign", 5);
Variables.WriteVariable(ptr_var->name, old_val);
}
}
@ -146,31 +147,32 @@ std::any EvalVisitor::visitExpr_stmt(Python3Parser::Expr_stmtContext *ctx) {
else if (ptr_dest_tuple) {
if (ptr_dest_tuple->size() !=
std::any_cast<std::vector<std::any>>(val).size())
throw InterpretException("visitExpr_stmt: Tuple size not match");
throw InterpretException("visitExpr_stmt: Tuple size not match", 6);
for (int j = 0; j < ptr_dest_tuple->size(); j++) {
ptr_dest_single = std::any_cast<RawVarible>(&(*ptr_dest_tuple)[j]);
if (!ptr_dest_single)
throw InterpretException(
"visitExpr_stmt: Expect left value at the left of assign");
"visitExpr_stmt: Expect left value at the left of assign", 7);
Variables.WriteVariable(ptr_dest_single->name,
std::any_cast<std::vector<std::any>>(val)[j]);
}
} else
throw InterpretException(
"visitExpr_stmt: Expect left value or tuple at the left of assign");
"visitExpr_stmt: Expect left value or tuple at the left of assign",
8);
}
return NoneType();
}
std::any EvalVisitor::visitAugassign(Python3Parser::AugassignContext *ctx) {
throw FatalError("Function visitAugassign Shouldn't be called");
throw FatalError("Function visitAugassign Shouldn't be called", 9);
}
std::any EvalVisitor::visitFlow_stmt(Python3Parser::Flow_stmtContext *ctx) {
if (ctx->break_stmt()) return visitBreak_stmt(ctx->break_stmt());
if (ctx->continue_stmt()) return visitContinue_stmt(ctx->continue_stmt());
if (ctx->return_stmt()) return visitReturn_stmt(ctx->return_stmt());
throw FatalError("Unknown flow statement");
throw FatalError("Unknown flow statement", 10);
return NoneType();
}
@ -200,7 +202,7 @@ std::any EvalVisitor::visitCompound_stmt(
if (ctx->if_stmt()) return visitIf_stmt(ctx->if_stmt());
if (ctx->while_stmt()) return visitWhile_stmt(ctx->while_stmt());
if (ctx->funcdef()) return visitFuncdef(ctx->funcdef());
throw FatalError("Unknown compound statement");
throw FatalError("Unknown compound statement", 11);
return NoneType();
}
@ -209,7 +211,7 @@ std::any EvalVisitor::visitIf_stmt(Python3Parser::If_stmtContext *ctx) {
auto suite_list = ctx->suite();
if (test_list.size() - suite_list.size() != -1 &&
test_list.size() - suite_list.size() != 0)
throw InterpretException("test and suite doesn't match in If_stmt");
throw InterpretException("test and suite doesn't match in If_stmt", 12);
for (int i = 0; i < test_list.size(); i++)
if (Any2Bool(DeQuate(visitTest(test_list[i]), Variables)))
return visitSuite(suite_list[i]);
@ -303,7 +305,7 @@ std::any EvalVisitor::visitComparison(Python3Parser::ComparisonContext *ctx) {
else if (op_list[i]->LT_EQ())
ok = LessEqual(last_val, cur);
else
throw InterpretException("visitComparison: Unknown operator");
throw InterpretException("visitComparison: Unknown operator", 13);
if (!ok) return false;
last_val = cur;
}
@ -311,7 +313,7 @@ std::any EvalVisitor::visitComparison(Python3Parser::ComparisonContext *ctx) {
}
std::any EvalVisitor::visitComp_op(Python3Parser::Comp_opContext *ctx) {
throw FatalError("Function visitComp_op Shouldn't be called");
throw FatalError("Function visitComp_op Shouldn't be called", 14);
}
std::any EvalVisitor::visitArith_expr(Python3Parser::Arith_exprContext *ctx) {
@ -328,13 +330,13 @@ std::any EvalVisitor::visitArith_expr(Python3Parser::Arith_exprContext *ctx) {
else if (op_list[i]->MINUS())
SelfSub(ans, cur);
else
throw FatalError("visitArith_expr: Unknown operator");
throw FatalError("visitArith_expr: Unknown operator", 15);
}
return ans;
}
std::any EvalVisitor::visitAddorsub_op(Python3Parser::Addorsub_opContext *ctx) {
throw FatalError("Function visitAddorsub_op Shouldn't be called");
throw FatalError("Function visitAddorsub_op Shouldn't be called", 16);
}
std::any EvalVisitor::visitTerm(Python3Parser::TermContext *ctx) {
@ -355,14 +357,14 @@ std::any EvalVisitor::visitTerm(Python3Parser::TermContext *ctx) {
else if (op_list[i]->MOD())
SelfMod(ans, cur);
else
throw FatalError("visitTerm: Unknown operator");
throw FatalError("visitTerm: Unknown operator", 17);
}
return ans;
}
std::any EvalVisitor::visitMuldivmod_op(
Python3Parser::Muldivmod_opContext *ctx) {
throw FatalError("Function visitMuldivmod_op Shouldn't be called");
throw FatalError("Function visitMuldivmod_op Shouldn't be called", 18);
}
std::any EvalVisitor::visitFactor(Python3Parser::FactorContext *ctx) {
@ -399,7 +401,7 @@ std::any EvalVisitor::visitArglist(Python3Parser::ArglistContext *ctx) {
std::any EvalVisitor::visitArgument(Python3Parser::ArgumentContext *ctx) {
auto arg_list = ctx->test();
if (arg_list.size() != 1 && arg_list.size() != 2)
throw FatalError("visitArgument: arg_list.size()!=1&&arg_list!=2");
throw FatalError("visitArgument: arg_list.size()!=1&&arg_list!=2", 19);
if (arg_list.size() == 1)
return ParaArguItemType("", DeQuate(visitTest(arg_list[0]), Variables));
else

View File

@ -1,34 +1,32 @@
#include <iostream>
#include "Evalvisitor.h"
#include "Python3Lexer.h"
#include "Python3Parser.h"
#include "antlr4-runtime.h"
#include <iostream>
#include "clipp/clipp.h"
using namespace antlr4;
// TODO: regenerating files in directory named "generated" is dangerous.
// if you really need to regenerate,please ask TA for help.
int main(int argc, char *argv[])
{
// TODO: please don't modify the code below the construction of ifs if you want to use visitor mode
int main(int argc, char *argv[]) {
// TODO: please don't modify the code below the construction of ifs if you
// want to use visitor mode
std::string input_file;
bool need_help = false;
auto cli = (clipp::option("-h", "--help").set(need_help).doc("show help") |
clipp::opt_value("input file", input_file));
if (!clipp::parse(argc, argv, cli))
{
if (!clipp::parse(argc, argv, cli)) {
std::cout << clipp::make_man_page(cli, argv[0]);
return 0;
}
if (need_help)
{
if (need_help) {
std::cout << clipp::make_man_page(cli, argv[0]);
return 0;
}
ANTLRInputStream *input_p;
if (input_file.length() == 0)
input_p = new ANTLRInputStream(std::cin);
else
{
else {
std::ifstream ifs(input_file);
input_p = new ANTLRInputStream(ifs);
}
@ -38,25 +36,22 @@ int main(int argc, char *argv[])
Python3Parser parser(&tokens);
tree::ParseTree *tree = parser.file_input();
EvalVisitor visitor;
try
{
try {
visitor.visit(tree);
}
catch (const InterpretException &e)
{
} catch (const InterpretException &e) {
std::cerr << "[Interpret Error] " << e.what() << std::endl;
}
catch (const FatalError &e)
{
std::cerr << "\e[7m\e[31m[Fatal Error] " << e.what() << "\e[0m" << std::endl;
}
catch (const std::exception &e)
{
std::cerr << "\e[7m\e[31m[other std::exception] " << e.what() << "\e[0m" << std::endl;
}
catch (...)
{
return e.GetCode();
} catch (const FatalError &e) {
std::cerr << "\e[7m\e[31m[Fatal Error] " << e.what() << "\e[0m"
<< std::endl;
return e.GetCode();
} catch (const std::exception &e) {
std::cerr << "\e[7m\e[31m[other std::exception] " << e.what() << "\e[0m"
<< std::endl;
return 255;
} catch (...) {
std::cerr << "\e[7m\e[31m[Unknown Exception]\e[0m" << std::endl;
return 255;
}
delete input_p;
return 0;

View File

@ -6,7 +6,7 @@ inline void VariableContainer::CreateFrame() {
StackScopes.push(std::unordered_map<std::string, std::any>());
}
void VariableContainer::DestroyFrame() {
if (StackScopes.empty()) throw FatalError("DestroyFrame: empty stack");
if (StackScopes.empty()) throw FatalError("DestroyFrame: empty stack", 20);
StackScopes.pop();
}
std::any VariableContainer::ReadVariable(const std::string &name) {
@ -15,7 +15,7 @@ std::any VariableContainer::ReadVariable(const std::string &name) {
if (top.find(name) != top.end()) return top[name];
}
if (GlobalScope.find(name) != GlobalScope.end()) return GlobalScope[name];
throw InterpretException(("ReadVariable: not found"));
throw InterpretException(("ReadVariable: not found"), 21);
}
void VariableContainer::WriteVariable(const std::string &name,
const std::any &value, bool cover) {
@ -41,7 +41,7 @@ void VariableContainer::WriteVariable(const std::string &name,
void FucntionContainer::AddFunction(const std::string &name,
const FunctionItem &item) {
if (FunctionIndex.find(name) != FunctionIndex.end()) {
throw InterpretException("AddFunction: function already exists");
throw InterpretException("AddFunction: function already exists", 22);
}
FunctionIndex[name] = item;
}
@ -66,32 +66,32 @@ std::any FucntionContainer::CallFunction(const std::string &name,
} else if (name == "str") {
if (args.size() != 1)
throw InterpretException(
"CallFunction: str() should take exactly one argument");
"CallFunction: str() should take exactly one argument", 23);
return Any2String(args[0].value);
} else if (name == "int") {
if (args.size() == 1) {
return Any2Int(args[0].value);
} else {
throw InterpretException(
"CallFunction: int() should take exactly one argument");
"CallFunction: int() should take exactly one argument", 24);
}
} else if (name == "float") {
if (args.size() == 1) {
return Any2Float(args[0].value);
} else {
throw InterpretException(
"CallFunction: float() should take exactly one argument");
"CallFunction: float() should take exactly one argument", 25);
}
} else if (name == "bool") {
if (args.size() == 1) {
return Any2Bool(args[0].value);
} else {
throw InterpretException(
"CallFunction: bool() should take exactly one argument");
"CallFunction: bool() should take exactly one argument", 26);
}
}
if (FunctionIndex.find(name) == FunctionIndex.end()) {
throw InterpretException("CallFunction: function not found");
throw InterpretException("CallFunction: function not found", 27);
}
const FunctionItem &func = FunctionIndex[name];
std::unordered_set<std::string> args_with_data;
@ -121,7 +121,8 @@ std::any FucntionContainer::CallFunction(const std::string &name,
i++;
if (i >= func.para_list.size()) break;
if (!func.para_list[i].value.has_value())
throw InterpretException("CallFunction: function parameter not found");
throw InterpretException("CallFunction: function parameter not found",
28);
Variables.WriteVariable(func.para_list[i].name, func.para_list[i].value,
true);
args_with_data.insert(func.para_list[i].name);

View File

@ -25,7 +25,7 @@ inline ZYM::int2048 Any2Int(const std::any &value) {
return std::move(ZYM::int2048(0));
else {
std::cerr << value.type().name() << std::endl;
throw FatalError("Any2Int2048: unknown type");
throw FatalError("Any2Int2048: unknown type", 29);
}
}
@ -48,7 +48,7 @@ double Any2Float(const std::any &value) {
else if (auto ptr = std::any_cast<std::string>(&value))
return std::stod(*ptr);
else
throw FatalError("Any2Float: unknown type");
throw FatalError("Any2Float: unknown type", 30);
}
std::string Any2String(const std::any &value) {
@ -68,7 +68,7 @@ std::string Any2String(const std::any &value) {
else if (auto ptr = std::any_cast<NoneType>(&value))
buf << "None";
else
throw FatalError("Any2String: unknown type");
throw FatalError("Any2String: unknown type", 31);
std::getline(buf, res);
return res;
}
@ -83,7 +83,7 @@ bool Any2Bool(const std::any &value) {
} else if (auto ptr = std::any_cast<std::string>(&value)) {
return (*ptr) != "";
} else
throw FatalError("Any2Bool: unknown type");
throw FatalError("Any2Bool: unknown type", 32);
}
std::any DeQuate(std::any val, VariableContainer &Variables) {
@ -115,16 +115,19 @@ int ConverToSameArithType(std::any &a, std::any &b,
if ((!allow_string_operation) && (ptr_a_string || ptr_b_string))
throw InterpretException(
"ConverToSameArithType: string operation not allowed in this "
"situation");
"situation",
33);
if (allow_string_operation && (ptr_a_string || ptr_b_string)) {
if (!(ptr_a_string || ptr_a_int2048))
throw InterpretException(
"ConverToSameArithType: string operation not allowed in this "
"situation");
"situation",
34);
if (!(ptr_b_string || ptr_b_int2048))
throw InterpretException(
"ConverToSameArithType: string operation not allowed in this "
"situation");
"situation",
35);
return 1;
}
int level_a = (ptr_a_bool != nullptr ? 1 : 0) +
@ -146,7 +149,7 @@ int ConverToSameArithType(std::any &a, std::any &b,
b = Any2Float(b);
break;
default:
throw FatalError("ConverToSameArithType: unknown type");
throw FatalError("ConverToSameArithType: unknown type", 36);
}
return 0;
}
@ -164,7 +167,7 @@ std::any Add(std::any a, std::any b) {
if ((ptr_a_string != nullptr ? 1 : 0) + (ptr_b_string != nullptr ? 1 : 0) ==
1) {
throw InterpretException(
"Add: string operation not allowed in this situation");
"Add: string operation not allowed in this situation", 37);
}
if ((ptr_a_string != nullptr ? 1 : 0) + (ptr_b_string != nullptr ? 1 : 0) ==
2)
@ -176,7 +179,7 @@ std::any Add(std::any a, std::any b) {
else if ((ptr_a_float != nullptr) && (ptr_b_float != nullptr))
return (*ptr_a_float) + (*ptr_b_float);
else
throw FatalError("Add: Type Error");
throw FatalError("Add: Type Error", 38);
}
std::any Sub(std::any a, std::any b) {
ConverToSameArithType(a, b);
@ -193,7 +196,7 @@ std::any Sub(std::any a, std::any b) {
else if ((ptr_a_float != nullptr) && (ptr_b_float != nullptr))
return (*ptr_a_float) - (*ptr_b_float);
else
throw FatalError("Sub: Type Error");
throw FatalError("Sub: Type Error", 39);
return a;
}
std::any Mul(std::any a, std::any b) {
@ -209,7 +212,7 @@ std::any Mul(std::any a, std::any b) {
if ((ptr_a_string != nullptr ? 1 : 0) + (ptr_b_string != nullptr ? 1 : 0) ==
2) {
throw InterpretException(
"Mul: string operation not allowed in this situation");
"Mul: string operation not allowed in this situation", 40);
} else if ((ptr_a_string != nullptr ? 1 : 0) +
(ptr_b_string != nullptr ? 1 : 0) ==
1) {
@ -220,7 +223,7 @@ std::any Mul(std::any a, std::any b) {
std::swap(ptr_a_float, ptr_b_float);
}
if (ptr_b_float != nullptr)
throw InterpretException("Mul: string*float not allowed");
throw InterpretException("Mul: string*float not allowed", 41);
if (ptr_b_bool != nullptr) {
if (*ptr_b_bool) {
return *ptr_a_string;
@ -241,7 +244,7 @@ std::any Mul(std::any a, std::any b) {
else if ((ptr_a_float != nullptr) && (ptr_b_float != nullptr))
return (*ptr_a_float) * (*ptr_b_float);
else
throw FatalError("Mul: Type Error");
throw FatalError("Mul: Type Error", 42);
}
std::any Div(std::any a, std::any b) {
bool *ptr_a_bool = std::any_cast<bool>(&a);
@ -254,10 +257,10 @@ std::any Div(std::any a, std::any b) {
std::string *ptr_b_string = std::any_cast<std::string>(&b);
if ((ptr_a_string != nullptr) || (ptr_b_string != nullptr))
throw InterpretException(
"Div: string operation not allowed in this situation");
"Div: string operation not allowed in this situation", 43);
double t_a = Any2Float(a);
double t_b = Any2Float(b);
if (t_b == 0) throw InterpretException("Div: divided by zero");
if (t_b == 0) throw InterpretException("Div: divided by zero", 44);
t_a = t_a / t_b;
return a;
}
@ -270,17 +273,19 @@ std::any Divv(std::any a, std::any b) {
double *ptr_a_float = std::any_cast<double>(&a);
double *ptr_b_float = std::any_cast<double>(&b);
if ((ptr_a_float != nullptr) && (ptr_b_float != nullptr)) {
if ((*ptr_b_float) == 0) throw InterpretException("Divv: divided by zero");
if ((*ptr_b_float) == 0)
throw InterpretException("Divv: divided by zero", 45);
return ZYM::int2048(std::floor((*ptr_a_float) / (*ptr_b_float)));
} else if ((ptr_a_int2048 != nullptr) && (ptr_b_int2048 != nullptr)) {
if ((*ptr_b_int2048) == 0)
throw InterpretException("Divv: divided by zero");
throw InterpretException("Divv: divided by zero", 46);
return (*ptr_a_int2048) / (*ptr_b_int2048);
} else if ((ptr_a_bool != nullptr) && (ptr_b_bool != nullptr)) {
if ((*ptr_b_bool) == 0) throw InterpretException("Divv: divided by zero");
if ((*ptr_b_bool) == 0)
throw InterpretException("Divv: divided by zero", 47);
return ZYM::int2048((*ptr_a_bool) / (*ptr_b_bool));
} else
throw FatalError("Divv: Type Error");
throw FatalError("Divv: Type Error", 48);
}
std::any Mod(std::any a, std::any b) {
ConverToSameArithType(a, b);
@ -291,18 +296,21 @@ std::any Mod(std::any a, std::any b) {
double *ptr_a_float = std::any_cast<double>(&a);
double *ptr_b_float = std::any_cast<double>(&b);
if ((ptr_a_float != nullptr) && (ptr_b_float != nullptr)) {
if ((*ptr_b_float) == 0) throw InterpretException("Mod: divided by zero");
if ((*ptr_b_float) == 0)
throw InterpretException("Mod: divided by zero", 49);
return ZYM::int2048((*ptr_a_float) -
(*ptr_b_float) *
std::floor((*ptr_a_float) / (*ptr_b_float)));
} else if ((ptr_a_int2048 != nullptr) && (ptr_b_int2048 != nullptr)) {
if ((*ptr_b_int2048) == 0) throw InterpretException("Mod: divided by zero");
if ((*ptr_b_int2048) == 0)
throw InterpretException("Mod: divided by zero", 50);
return (*ptr_a_int2048) % (*ptr_b_int2048);
} else if ((ptr_a_bool != nullptr) && (ptr_b_bool != nullptr)) {
if ((*ptr_b_bool) == 0) throw InterpretException("Mod: divided by zero");
if ((*ptr_b_bool) == 0)
throw InterpretException("Mod: divided by zero", 51);
return ZYM::int2048((*ptr_a_bool) % (*ptr_b_bool));
} else
throw FatalError("Mod: Type Error");
throw FatalError("Mod: Type Error", 52);
}
std::any &SelfAdd(std::any &a, std::any b) {
a = Add(a, b);
@ -339,7 +347,7 @@ std::any Neg(std::any a) {
else if (ptr_a_float != nullptr)
return -(*ptr_a_float);
else
throw FatalError("Neg: Type Error");
throw FatalError("Neg: Type Error", 53);
}
bool Greater(std::any a, std::any b) {
@ -361,7 +369,7 @@ bool Greater(std::any a, std::any b) {
else if ((ptr_a_string != nullptr) && (ptr_b_string != nullptr))
return (*ptr_a_string) > (*ptr_b_string);
else
throw FatalError("Greater: Type Error");
throw FatalError("Greater: Type Error", 54);
}
bool Less(std::any a, std::any b) {
ConverToSameArithType(a, b, true);
@ -382,7 +390,7 @@ bool Less(std::any a, std::any b) {
else if ((ptr_a_string != nullptr) && (ptr_b_string != nullptr))
return (*ptr_a_string) < (*ptr_b_string);
else
throw FatalError("Less: Type Error");
throw FatalError("Less: Type Error", 55);
}
bool Equal(std::any a, std::any b) {
ConverToSameArithType(a, b, true);
@ -403,7 +411,7 @@ bool Equal(std::any a, std::any b) {
else if ((ptr_a_string != nullptr) && (ptr_b_string != nullptr))
return (*ptr_a_string) == (*ptr_b_string);
else
throw FatalError("Equal: Type Error");
throw FatalError("Equal: Type Error", 56);
}
bool NotEqual(std::any a, std::any b) {
ConverToSameArithType(a, b, true);
@ -424,7 +432,7 @@ bool NotEqual(std::any a, std::any b) {
else if ((ptr_a_string != nullptr) && (ptr_b_string != nullptr))
return (*ptr_a_string) != (*ptr_b_string);
else
throw FatalError("NotEqual: Type Error");
throw FatalError("NotEqual: Type Error", 57);
}
bool GreaterEqual(std::any a, std::any b) {
ConverToSameArithType(a, b, true);
@ -445,7 +453,7 @@ bool GreaterEqual(std::any a, std::any b) {
else if ((ptr_a_string != nullptr) && (ptr_b_string != nullptr))
return (*ptr_a_string) >= (*ptr_b_string);
else
throw FatalError("GreaterEqual: Type Error");
throw FatalError("GreaterEqual: Type Error", 58);
}
bool LessEqual(std::any a, std::any b) {
ConverToSameArithType(a, b, true);
@ -466,5 +474,5 @@ bool LessEqual(std::any a, std::any b) {
else if ((ptr_a_string != nullptr) && (ptr_b_string != nullptr))
return (*ptr_a_string) <= (*ptr_b_string);
else
throw FatalError("LessEqual: Type Error");
throw FatalError("LessEqual: Type Error", 59);
}