diff --git a/include/utils.h b/include/utils.h index 740b4fc..cf05266 100644 --- a/include/utils.h +++ b/include/utils.h @@ -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 { diff --git a/src/Evalvisitor.cpp b/src/Evalvisitor.cpp index 944dceb..568bd0e 100644 --- a/src/Evalvisitor.cpp +++ b/src/Evalvisitor.cpp @@ -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>(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(&(*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>(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>(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(&(*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>(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 diff --git a/src/main.cpp b/src/main.cpp index cecdff2..077c337 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,34 +1,32 @@ +#include + #include "Evalvisitor.h" #include "Python3Lexer.h" #include "Python3Parser.h" #include "antlr4-runtime.h" -#include #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; diff --git a/src/names.cpp b/src/names.cpp index 3d43018..1ca32da 100644 --- a/src/names.cpp +++ b/src/names.cpp @@ -6,7 +6,7 @@ inline void VariableContainer::CreateFrame() { StackScopes.push(std::unordered_map()); } 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 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); diff --git a/src/utils.cpp b/src/utils.cpp index 376d6ff..6da525b 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -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(&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(&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(&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(&a); @@ -254,10 +257,10 @@ std::any Div(std::any a, std::any b) { std::string *ptr_b_string = std::any_cast(&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(&a); double *ptr_b_float = std::any_cast(&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(&a); double *ptr_b_float = std::any_cast(&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); } \ No newline at end of file