diff --git a/fig-vscode/package.json b/fig-vscode/package.json index f5eb4e5..ec0bc29 100644 --- a/fig-vscode/package.json +++ b/fig-vscode/package.json @@ -2,7 +2,7 @@ "name": "fig-vscode", "displayName": "Fig Language", "description": "VSCode extension for Fig language with syntax highlighting", - "version": "0.4.2", + "version": "0.4.3", "publisher": "PuqiAR", "engines": { "vscode": "^1.90.0" diff --git a/fig-vscode/syntaxes/fig.tmLanguage.json b/fig-vscode/syntaxes/fig.tmLanguage.json index 2404f07..34c8de8 100644 --- a/fig-vscode/syntaxes/fig.tmLanguage.json +++ b/fig-vscode/syntaxes/fig.tmLanguage.json @@ -57,7 +57,7 @@ "patterns": [ { "name": "keyword.control.fig", - "match": "\\b(and|or|not|import|func|var|const|final|while|for|if|else|new|struct|interface|impl|public|return|break|continue|try|catch|throw)\\b" + "match": "\\b(and|or|not|import|func|var|const|final|while|for|if|else|new|struct|interface|impl|public|return|break|continue|try|catch|throw|is|as)\\b" }, { "name": "constant.language.fig", "match": "\\b(true|false|null)\\b" } ] @@ -78,7 +78,7 @@ }, { "name": "keyword.operator.comparison.fig", - "match": "(==|!=|<=|>=|<|>|is)" + "match": "(==|!=|<=|>=|<|>)" }, { "name": "punctuation.separator.fig", diff --git a/src/Ast/Statements/ImportSt.hpp b/src/Ast/Statements/ImportSt.hpp index e0946e9..57338f7 100644 --- a/src/Ast/Statements/ImportSt.hpp +++ b/src/Ast/Statements/ImportSt.hpp @@ -6,18 +6,26 @@ namespace Fig::Ast { + /* + import std.io as stdio; // io --> stdio; + import std.io {print, println}; + */ + class ImportSt final : public StatementAst { public: std::vector path; + std::vector names; + + FString rename; ImportSt() { type = AstType::ImportSt; } - ImportSt(std::vector _path) : - path(std::move(_path)) + ImportSt(std::vector _path, std::vector _names, const FString &_rename) : + path(std::move(_path)), names(std::move(_names)), rename(_rename) { type = AstType::ImportSt; } diff --git a/src/Ast/astBase.hpp b/src/Ast/astBase.hpp index a406b44..5c059ce 100644 --- a/src/Ast/astBase.hpp +++ b/src/Ast/astBase.hpp @@ -35,7 +35,7 @@ namespace Fig::Ast TupleExpr, // (1, 2, 3) MapExpr, // {a: 1} - InitExpr, // struct{"123", 456} + InitExpr, // struct{"123", 456} FunctionLiteralExpr, /* Statement */ @@ -199,6 +199,9 @@ namespace Fig::Ast GreaterEqual, // >= Is, // a is b + // 转换 + As, // 3.14 as Int + // 三目 TernaryCond, @@ -235,6 +238,8 @@ namespace Fig::Ast Operator::Equal, Operator::NotEqual, Operator::Less, Operator::LessEqual, Operator::Greater, Operator::GreaterEqual, Operator::Is, + Operator::As, + Operator::BitAnd, Operator::BitOr, Operator::BitXor, Operator::BitNot, Operator::ShiftLeft, Operator::ShiftRight, @@ -271,6 +276,9 @@ namespace Fig::Ast {TokenType::GreaterEqual, Operator::GreaterEqual}, {TokenType::Is, Operator::Is}, + // 转换 + {TokenType::As, Operator::As}, + // 三目 {TokenType::Question, Operator::TernaryCond}, diff --git a/src/Error/errorLog.hpp b/src/Error/errorLog.hpp index a019fb4..918d2d5 100644 --- a/src/Error/errorLog.hpp +++ b/src/Error/errorLog.hpp @@ -97,6 +97,14 @@ namespace Fig std::print("{}{}{}", colorCode, msg, TerminalColors::Reset); } + inline void logFigErrorInterface(const FString &errorClass, const FString &errorMessage) + { + namespace TC = TerminalColors; + coloredPrint(TC::LightWhite, "Uncaught Fig exception:\n"); + coloredPrint(TC::LightRed, "✖ "); + coloredPrint(TC::Red, errorClass.toBasicString() + ": "); + coloredPrint(TC::Red, errorMessage.toBasicString() + "\n"); + } inline void logAddressableError(const AddressableError &err) { @@ -117,7 +125,6 @@ namespace Fig if (fileName != u8"") { lineContent = ((int64_t(err.getLine()) - int64_t(1)) >= 0 ? sourceLines[err.getLine() - 1] : u8""); - FString pointerLine; for (size_t i = 1; i < err.getColumn(); ++i) { if (lineContent[i - 1] == U'\t') { pointerLine += U'\t'; } diff --git a/src/Evaluator/Context/context.hpp b/src/Evaluator/Context/context.hpp index 6262f58..ac4762a 100644 --- a/src/Evaluator/Context/context.hpp +++ b/src/Evaluator/Context/context.hpp @@ -16,6 +16,7 @@ #include #include #include +#include namespace Fig { @@ -30,8 +31,8 @@ namespace Fig struct OperationRecord { - using UnaryOpFn = std::function; - using BinaryOpFn = std::function; + using UnaryOpFn = std::function; + using BinaryOpFn = std::function; std::unordered_map unOpRec; std::unordered_map binOpRec; diff --git a/src/Evaluator/Core/Eval.cpp b/src/Evaluator/Core/Eval.cpp index 5044dbe..1e5f823 100644 --- a/src/Evaluator/Core/Eval.cpp +++ b/src/Evaluator/Core/Eval.cpp @@ -1,9 +1,10 @@ #include #include +#include namespace Fig { - RvObject Evaluator::eval(Ast::Expression exp, ContextPtr ctx) + ExprResult Evaluator::eval(Ast::Expression exp, ContextPtr ctx) { using Ast::AstType; AstType type = exp->getType(); @@ -16,8 +17,8 @@ namespace Fig } case AstType::VarExpr: { auto varExpr = std::static_pointer_cast(exp); - - return evalVarExpr(varExpr, ctx).get(); // LvObject -> RvObject + + return check_unwrap_lv(evalVarExpr(varExpr, ctx)).get(); // LvObject -> RvObject } case AstType::BinaryExpr: { auto bin = std::static_pointer_cast(exp); @@ -35,7 +36,7 @@ namespace Fig return evalTernary(te, ctx); } case AstType::MemberExpr: - case AstType::IndexExpr: return evalLv(exp, ctx).get(); + case AstType::IndexExpr: return check_unwrap_lv(evalLv(exp, ctx)).get(); case AstType::FunctionCall: { auto fnCall = std::static_pointer_cast(exp); @@ -82,7 +83,7 @@ namespace Fig List list; - for (auto &exp : lstExpr->val) { list.push_back(eval(exp, ctx)); } + for (auto &exp : lstExpr->val) { list.push_back(check_unwrap(eval(exp, ctx))); } return std::make_shared(std::move(list)); } @@ -91,7 +92,9 @@ namespace Fig Map map; - for (auto &[key, value] : mapExpr->val) { map[eval(key, ctx)] = eval(value, ctx); } + for (auto &[key, value] : mapExpr->val) { + map[check_unwrap(eval(key, ctx))] = check_unwrap(eval(value, ctx)); + } return std::make_shared(std::move(map)); } diff --git a/src/Evaluator/Core/EvalBinary.cpp b/src/Evaluator/Core/EvalBinary.cpp index dbaef63..544d245 100644 --- a/src/Evaluator/Core/EvalBinary.cpp +++ b/src/Evaluator/Core/EvalBinary.cpp @@ -1,23 +1,27 @@ #include #include +#include +#include #include #include #include #include +#include +#include #include #include namespace Fig { - RvObject Evaluator::evalBinary(Ast::BinaryExpr bin, ContextPtr ctx) + ExprResult Evaluator::evalBinary(Ast::BinaryExpr bin, ContextPtr ctx) { using Ast::Operator; Operator op = bin->op; Ast::Expression lexp = bin->lexp, rexp = bin->rexp; const auto &tryInvokeOverloadFn = - [ctx, op](const ObjectPtr &lhs, const ObjectPtr &rhs, const std::function &rollback) { + [ctx, op](const ObjectPtr &lhs, const ObjectPtr &rhs, const std::function &rollback) { if (lhs->is() && lhs->getTypeInfo() == rhs->getTypeInfo()) { // 运算符重载 @@ -34,8 +38,8 @@ namespace Fig switch (op) { case Operator::Add: { - ObjectPtr lhs = eval(lexp, ctx); - ObjectPtr rhs = eval(rexp, ctx); + ObjectPtr lhs = check_unwrap(eval(lexp, ctx)); + ObjectPtr rhs = check_unwrap(eval(rexp, ctx)); return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { if (lhs->is() && rhs->is()) { @@ -46,8 +50,8 @@ namespace Fig }); } case Operator::Subtract: { - ObjectPtr lhs = eval(lexp, ctx); - ObjectPtr rhs = eval(rexp, ctx); + ObjectPtr lhs = check_unwrap(eval(lexp, ctx)); + ObjectPtr rhs = check_unwrap(eval(rexp, ctx)); return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { if (lhs->is() && rhs->is()) { @@ -58,8 +62,8 @@ namespace Fig }); } case Operator::Multiply: { - ObjectPtr lhs = eval(lexp, ctx); - ObjectPtr rhs = eval(rexp, ctx); + ObjectPtr lhs = check_unwrap(eval(lexp, ctx)); + ObjectPtr rhs = check_unwrap(eval(rexp, ctx)); return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { if (lhs->is() && rhs->is()) { @@ -70,13 +74,13 @@ namespace Fig }); } case Operator::Divide: { - ObjectPtr lhs = eval(lexp, ctx); - ObjectPtr rhs = eval(rexp, ctx); + ObjectPtr lhs = check_unwrap(eval(lexp, ctx)); + ObjectPtr rhs = check_unwrap(eval(rexp, ctx)); return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared(*lhs / *rhs); }); } case Operator::Modulo: { - ObjectPtr lhs = eval(lexp, ctx); - ObjectPtr rhs = eval(rexp, ctx); + ObjectPtr lhs = check_unwrap(eval(lexp, ctx)); + ObjectPtr rhs = check_unwrap(eval(rexp, ctx)); return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { if (lhs->is() && rhs->is()) { @@ -93,8 +97,8 @@ namespace Fig } case Operator::Is: { - ObjectPtr lhs = eval(lexp, ctx); - ObjectPtr rhs = eval(rexp, ctx); + ObjectPtr lhs = check_unwrap(eval(lexp, ctx)); + ObjectPtr rhs = check_unwrap(eval(rexp, ctx)); return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs, ctx, bin]() { const TypeInfo &lhsType = lhs->getTypeInfo(); @@ -143,9 +147,114 @@ namespace Fig }); } + case Operator::As: { + ObjectPtr lhs = check_unwrap(eval(lexp, ctx)); + ObjectPtr rhs = check_unwrap(eval(rexp, ctx)); + + return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs, ctx, bin, this]() -> ExprResult { + if (!rhs->is()) + { + throw EvaluatorError( + u8"OperatorError", + std::format("Operator `as` requires right hand side operand a struct type, but got '{}'", + prettyType(rhs).toBasicString()), + bin->rexp); + } + const StructType &targetStructType = rhs->as(); + const TypeInfo &targetType = targetStructType.type; + const TypeInfo &sourceType = lhs->getTypeInfo(); + if (targetType == sourceType) { return lhs; } + if (targetType == ValueType::String) { return std::make_shared(lhs->toStringIO()); } + if (sourceType == ValueType::Int) + { + if (targetType == ValueType::Double) + { + return std::make_shared( + static_cast(lhs->as())); + } + } + else if (sourceType == ValueType::Double) + { + if (targetType == ValueType::Int) + { + return IntPool::getInstance().createInt( + static_cast(lhs->as())); + } + } + else if (sourceType == ValueType::String) + { + const FString &str = lhs->as(); + if (targetType == ValueType::Int) + { + try + { + return IntPool::getInstance().createInt( + static_cast(std::stoll(str.toBasicString()))); + } + catch (std::exception &e) + { + return ExprResult::error( + genTypeError(FString(std::format("Cannot cast type `{}` to `{}`, bad int string {}", + prettyType(lhs).toBasicString(), + prettyType(rhs).toBasicString(), + str.toBasicString())), + bin->rexp, + ctx)); + } + } + if (targetType == ValueType::Double) + { + try + { + return std::make_shared(std::stod(str.toBasicString())); + } + catch (std::exception &e) + { + return ExprResult::error(genTypeError( + FString(std::format("Cannot cast type `{}` to `{}`, bad double string {}", + prettyType(lhs).toBasicString(), + prettyType(rhs).toBasicString(), + str.toBasicString())), + bin->rexp, + ctx)); + } + } + if (targetType == ValueType::Bool) + { + if (str == u8"true") { return Object::getTrueInstance(); } + else if (str == u8"false") { return Object::getFalseInstance(); } + return ExprResult::error( + genTypeError(FString(std::format("Cannot cast type `{}` to `{}`, bad bool string {}", + prettyType(lhs).toBasicString(), + prettyType(rhs).toBasicString(), + str.toBasicString())), + bin->rexp, + ctx)); + } + } + else if (sourceType == ValueType::Bool) + { + if (targetType == ValueType::Int) + { + return IntPool::getInstance().createInt(static_cast(lhs->as())); + } + if (targetType == ValueType::Double) + { + return std::make_shared(static_cast(lhs->as())); + } + } + + return ExprResult::error(genTypeError(FString(std::format("Cannot cast type `{}` to `{}`", + prettyType(lhs).toBasicString(), + prettyType(rhs).toBasicString())), + bin->rexp, + ctx)); + }); + } + case Operator::BitAnd: { - ObjectPtr lhs = eval(lexp, ctx); - ObjectPtr rhs = eval(rexp, ctx); + ObjectPtr lhs = check_unwrap(eval(lexp, ctx)); + ObjectPtr rhs = check_unwrap(eval(rexp, ctx)); return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { if (lhs->is() && rhs->is()) @@ -156,9 +265,10 @@ namespace Fig return std::make_shared(bit_and(*lhs, *rhs)); }); } + case Operator::BitOr: { - ObjectPtr lhs = eval(lexp, ctx); - ObjectPtr rhs = eval(rexp, ctx); + ObjectPtr lhs = check_unwrap(eval(lexp, ctx)); + ObjectPtr rhs = check_unwrap(eval(rexp, ctx)); return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { if (lhs->is() && rhs->is()) @@ -169,9 +279,10 @@ namespace Fig return std::make_shared(bit_or(*lhs, *rhs)); }); } + case Operator::BitXor: { - ObjectPtr lhs = eval(lexp, ctx); - ObjectPtr rhs = eval(rexp, ctx); + ObjectPtr lhs = check_unwrap(eval(lexp, ctx)); + ObjectPtr rhs = check_unwrap(eval(rexp, ctx)); return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { if (lhs->is() && rhs->is()) @@ -182,9 +293,10 @@ namespace Fig return std::make_shared(bit_xor(*lhs, *rhs)); }); } + case Operator::ShiftLeft: { - ObjectPtr lhs = eval(lexp, ctx); - ObjectPtr rhs = eval(rexp, ctx); + ObjectPtr lhs = check_unwrap(eval(lexp, ctx)); + ObjectPtr rhs = check_unwrap(eval(rexp, ctx)); return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { if (lhs->is() && rhs->is()) @@ -196,8 +308,8 @@ namespace Fig }); } case Operator::ShiftRight: { - ObjectPtr lhs = eval(lexp, ctx); - ObjectPtr rhs = eval(rexp, ctx); + ObjectPtr lhs = check_unwrap(eval(lexp, ctx)); + ObjectPtr rhs = check_unwrap(eval(rexp, ctx)); return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { if (lhs->is() && rhs->is()) @@ -210,99 +322,112 @@ namespace Fig } case Operator::Assign: { - LvObject lv = evalLv(lexp, ctx); - ObjectPtr rhs = eval(rexp, ctx); + LvObject lv = check_unwrap_lv(evalLv(lexp, ctx)); + ObjectPtr rhs = check_unwrap(eval(rexp, ctx)); lv.set(rhs); return rhs; } case Operator::And: { - ObjectPtr lhs = eval(lexp, ctx); + ObjectPtr lhs = check_unwrap(eval(lexp, ctx)); if (lhs->is() && !isBoolObjectTruthy(lhs)) { return Object::getFalseInstance(); } - ObjectPtr rhs = eval(rexp, ctx); + ObjectPtr rhs = check_unwrap(eval(rexp, ctx)); return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared(*lhs && *rhs); }); } + case Operator::Or: { - ObjectPtr lhs = eval(lexp, ctx); + ObjectPtr lhs = check_unwrap(eval(lexp, ctx)); if (lhs->is() && isBoolObjectTruthy(lhs)) { return Object::getTrueInstance(); } - ObjectPtr rhs = eval(rexp, ctx); + ObjectPtr rhs = check_unwrap(eval(rexp, ctx)); return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared(*lhs || *rhs); }); } + case Operator::Equal: { - ObjectPtr lhs = eval(lexp, ctx); - ObjectPtr rhs = eval(rexp, ctx); + ObjectPtr lhs = check_unwrap(eval(lexp, ctx)); + ObjectPtr rhs = check_unwrap(eval(rexp, ctx)); return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared(*lhs == *rhs); }); } + case Operator::NotEqual: { - ObjectPtr lhs = eval(lexp, ctx); - ObjectPtr rhs = eval(rexp, ctx); + ObjectPtr lhs = check_unwrap(eval(lexp, ctx)); + ObjectPtr rhs = check_unwrap(eval(rexp, ctx)); return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared(*lhs != *rhs); }); } + case Operator::Less: { - ObjectPtr lhs = eval(lexp, ctx); - ObjectPtr rhs = eval(rexp, ctx); + ObjectPtr lhs = check_unwrap(eval(lexp, ctx)); + ObjectPtr rhs = check_unwrap(eval(rexp, ctx)); return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared(*lhs < *rhs); }); } + case Operator::LessEqual: { - ObjectPtr lhs = eval(lexp, ctx); - ObjectPtr rhs = eval(rexp, ctx); + ObjectPtr lhs = check_unwrap(eval(lexp, ctx)); + ObjectPtr rhs = check_unwrap(eval(rexp, ctx)); return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared(*lhs <= *rhs); }); } + case Operator::Greater: { - ObjectPtr lhs = eval(lexp, ctx); - ObjectPtr rhs = eval(rexp, ctx); + ObjectPtr lhs = check_unwrap(eval(lexp, ctx)); + ObjectPtr rhs = check_unwrap(eval(rexp, ctx)); return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared(*lhs > *rhs); }); } + case Operator::GreaterEqual: { - ObjectPtr lhs = eval(lexp, ctx); - ObjectPtr rhs = eval(rexp, ctx); + ObjectPtr lhs = check_unwrap(eval(lexp, ctx)); + ObjectPtr rhs = check_unwrap(eval(rexp, ctx)); return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared(*lhs >= *rhs); }); } + case Operator::PlusAssign: { - LvObject lv = evalLv(lexp, ctx); + LvObject lv = check_unwrap_lv(evalLv(lexp, ctx)); const ObjectPtr &lhs = lv.get(); - ObjectPtr rhs = eval(rexp, ctx); - const ObjectPtr &result = - tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared(*lhs + *rhs); }); + ObjectPtr rhs = check_unwrap(eval(rexp, ctx)); + const ObjectPtr &result = check_unwrap( + tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared(*lhs + *rhs); })); lv.set(result); return rhs; } + case Operator::MinusAssign: { - LvObject lv = evalLv(lexp, ctx); + LvObject lv = check_unwrap_lv(evalLv(lexp, ctx)); const ObjectPtr &lhs = lv.get(); - ObjectPtr rhs = eval(rexp, ctx); - const ObjectPtr &result = - tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared(*lhs - *rhs); }); + ObjectPtr rhs = check_unwrap(eval(rexp, ctx)); + const ObjectPtr &result = check_unwrap( + tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared(*lhs - *rhs); })); lv.set(result); return rhs; } + case Operator::AsteriskAssign: { - LvObject lv = evalLv(lexp, ctx); + LvObject lv = check_unwrap_lv(evalLv(lexp, ctx)); const ObjectPtr &lhs = lv.get(); - ObjectPtr rhs = eval(rexp, ctx); - const ObjectPtr &result = - tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared(*lhs * *rhs); }); + ObjectPtr rhs = check_unwrap(eval(rexp, ctx)); + const ObjectPtr &result = check_unwrap( + tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared(*lhs * *rhs); })); lv.set(result); return rhs; } + case Operator::SlashAssign: { - LvObject lv = evalLv(lexp, ctx); + LvObject lv = check_unwrap_lv(evalLv(lexp, ctx)); const ObjectPtr &lhs = lv.get(); - ObjectPtr rhs = eval(rexp, ctx); - const ObjectPtr &result = - tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared(*lhs / *rhs); }); + ObjectPtr rhs = check_unwrap(eval(rexp, ctx)); + const ObjectPtr &result = check_unwrap( + tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared(*lhs / *rhs); })); lv.set(result); return rhs; } + case Operator::PercentAssign: { - LvObject lv = evalLv(lexp, ctx); + LvObject lv = check_unwrap_lv(evalLv(lexp, ctx)); const ObjectPtr &lhs = lv.get(); - ObjectPtr rhs = eval(rexp, ctx); - const ObjectPtr &result = - tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared(*lhs % *rhs); }); + ObjectPtr rhs = check_unwrap(eval(rexp, ctx)); + const ObjectPtr &result = check_unwrap( + tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared(*lhs % *rhs); })); lv.set(result); return rhs; } + default: throw EvaluatorError(u8"UnsupportedOp", std::format("Unsupport operator '{}' for binary", magic_enum::enum_name(op)), diff --git a/src/Evaluator/Core/EvalFunctionCall.cpp b/src/Evaluator/Core/EvalFunctionCall.cpp index c6a8da6..01e10e0 100644 --- a/src/Evaluator/Core/EvalFunctionCall.cpp +++ b/src/Evaluator/Core/EvalFunctionCall.cpp @@ -5,10 +5,11 @@ #include #include #include +#include namespace Fig { - RvObject Evaluator::executeFunction(const Function &fn, + ExprResult Evaluator::executeFunction(const Function &fn, const Ast::FunctionCallArgs &args, ContextPtr fnCtx) // new context for fn, already filled paras { @@ -28,9 +29,7 @@ namespace Fig StatementResult sr = evalStatement(stmt, fnCtx); if (sr.isError()) { - throw EvaluatorError(u8"UncaughtExceptionError", - std::format("Uncaught exception: {}", sr.result->toString().toBasicString()), - stmt); + handle_error(sr, stmt, fnCtx); } if (!sr.isNormal()) { @@ -39,9 +38,9 @@ namespace Fig } return Object::getNullInstance(); } - RvObject Evaluator::evalFunctionCall(const Ast::FunctionCall &call, ContextPtr ctx) + ExprResult Evaluator::evalFunctionCall(const Ast::FunctionCall &call, ContextPtr ctx) { - RvObject fnObj = eval(call->callee, ctx); + RvObject fnObj = check_unwrap(eval(call->callee, ctx)); if (fnObj->getTypeInfo() != ValueType::Function) { throw EvaluatorError(u8"ObjectNotCallable", @@ -57,7 +56,7 @@ namespace Fig Ast::FunctionCallArgs evaluatedArgs; if (fn.type == Function::Builtin || fn.type == Function::MemberType) { - for (const auto &argExpr : fnArgs.argv) { evaluatedArgs.argv.push_back(eval(argExpr, ctx)); } + for (const auto &argExpr : fnArgs.argv) { evaluatedArgs.argv.push_back(check_unwrap(eval(argExpr, ctx))); } if (fn.builtinParamCount != -1 && fn.builtinParamCount != evaluatedArgs.getLength()) { throw EvaluatorError(u8"BuiltinArgumentMismatchError", @@ -96,9 +95,9 @@ namespace Fig size_t i; for (i = 0; i < fnParas.posParas.size(); i++) { - const TypeInfo &expectedType = actualType(eval(fnParas.posParas[i].second, fn.closureContext)); // look up type info, if exists a type + const TypeInfo &expectedType = actualType(check_unwrap(eval(fnParas.posParas[i].second, fn.closureContext))); // look up type info, if exists a type // with the name, use it, else throw - ObjectPtr argVal = eval(fnArgs.argv[i], ctx); + ObjectPtr argVal = check_unwrap(eval(fnArgs.argv[i], ctx)); TypeInfo actualType = argVal->getTypeInfo(); if (!isTypeMatch(expectedType, argVal, fn.closureContext)) { @@ -116,9 +115,10 @@ namespace Fig for (; i < fnArgs.getLength(); i++) { size_t defParamIndex = i - fnParas.posParas.size(); - const TypeInfo &expectedType = actualType(eval(fnParas.defParas[defParamIndex].second.first, fn.closureContext)); + const TypeInfo &expectedType = + actualType(check_unwrap(eval(fnParas.defParas[defParamIndex].second.first, fn.closureContext))); - ObjectPtr defaultVal = eval(fnParas.defParas[defParamIndex].second.second, fn.closureContext); + ObjectPtr defaultVal = check_unwrap(eval(fnParas.defParas[defParamIndex].second.second, fn.closureContext)); if (!isTypeMatch(expectedType, defaultVal, fn.closureContext)) { throw EvaluatorError( @@ -132,7 +132,7 @@ namespace Fig fnArgs.argv[i]); } - ObjectPtr argVal = eval(fnArgs.argv[i], ctx); + ObjectPtr argVal = check_unwrap(eval(fnArgs.argv[i], ctx)); TypeInfo actualType = argVal->getTypeInfo(); if (!isTypeMatch(expectedType, argVal, fn.closureContext)) { @@ -150,7 +150,7 @@ namespace Fig for (; i < fnParas.size(); i++) { size_t defParamIndex = i - fnParas.posParas.size(); - ObjectPtr defaultVal = eval(fnParas.defParas[defParamIndex].second.second, fn.closureContext); + ObjectPtr defaultVal = check_unwrap(eval(fnParas.defParas[defParamIndex].second.second, fn.closureContext)); evaluatedArgs.argv.push_back(defaultVal); } @@ -162,13 +162,14 @@ namespace Fig if (j < fnParas.posParas.size()) { paramName = fnParas.posParas[j].first; - paramType = actualType(eval(fnParas.posParas[j].second, fn.closureContext)); + paramType = actualType(check_unwrap(eval(fnParas.posParas[j].second, fn.closureContext))); } else { size_t defParamIndex = j - fnParas.posParas.size(); paramName = fnParas.defParas[defParamIndex].first; - paramType = actualType(eval(fnParas.defParas[defParamIndex].second.first, fn.closureContext)); + paramType = + actualType(check_unwrap(eval(fnParas.defParas[defParamIndex].second.first, fn.closureContext))); } AccessModifier argAm = AccessModifier::Normal; newContext->def(paramName, paramType, argAm, evaluatedArgs.argv[j]); @@ -180,7 +181,7 @@ namespace Fig List list; for (auto &exp : fnArgs.argv) { - list.push_back(eval(exp, ctx)); // eval arguments in current scope + list.push_back(check_unwrap(eval(exp, ctx))); // eval arguments in current scope } newContext->def(fnParas.variadicPara, ValueType::List, AccessModifier::Normal, std::make_shared(list)); goto ExecuteBody; @@ -188,7 +189,7 @@ namespace Fig ExecuteBody: { // execute function body - ObjectPtr retVal = executeFunction(fn, evaluatedArgs, newContext); + ObjectPtr retVal = check_unwrap(executeFunction(fn, evaluatedArgs, newContext)); if (!isTypeMatch(fn.retType, retVal, ctx)) { diff --git a/src/Evaluator/Core/EvalInitExpr.cpp b/src/Evaluator/Core/EvalInitExpr.cpp index 60cd005..f6acc51 100644 --- a/src/Evaluator/Core/EvalInitExpr.cpp +++ b/src/Evaluator/Core/EvalInitExpr.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -5,9 +6,9 @@ namespace Fig { - RvObject Evaluator::evalInitExpr(Ast::InitExpr initExpr, ContextPtr ctx) + ExprResult Evaluator::evalInitExpr(Ast::InitExpr initExpr, ContextPtr ctx) { - LvObject structeLv = evalLv(initExpr->structe, ctx); + LvObject structeLv = check_unwrap_lv(evalLv(initExpr->structe, ctx)); ObjectPtr structTypeVal = structeLv.get(); const FString &structName = structeLv.name(); if (!structTypeVal->is()) @@ -46,7 +47,7 @@ namespace Fig return std::make_shared(Object::defaultValue(type)); } - ObjectPtr val = eval(args[0].second, ctx); + ObjectPtr val = check_unwrap(eval(args[0].second, ctx)); auto err = [&](const char *msg) { throw EvaluatorError(u8"BuiltinInitTypeMismatchError", @@ -150,11 +151,12 @@ namespace Fig std::vector> evaluatedArgs; - auto evalArguments = [&evaluatedArgs, initExpr, ctx, this]() { + auto evalArguments = [&evaluatedArgs, initExpr, ctx, this](){ for (const auto &[argName, argExpr] : initExpr->args) { - evaluatedArgs.push_back({argName, eval(argExpr, ctx)}); + evaluatedArgs.push_back({argName, check_unwrap(eval(argExpr, ctx))}); } + return ExprResult::normal(Object::getNullInstance()); }; ContextPtr instanceCtx = @@ -182,8 +184,8 @@ namespace Fig // must be a default value // evaluate default value in definition context - ObjectPtr defaultVal = eval(field.defaultValue, - ctx); // it can't be null here + ObjectPtr defaultVal = check_unwrap(eval(field.defaultValue, + ctx)); // it can't be null here // type check if (!isTypeMatch(expectedType, defaultVal, ctx)) @@ -238,8 +240,8 @@ namespace Fig { // use default value // // evaluate default value in definition context - ObjectPtr defaultVal = eval(field.defaultValue, - defContext); // it can't be null here + ObjectPtr defaultVal = check_unwrap(eval(field.defaultValue, + defContext)); // it can't be null here // type check const TypeInfo &expectedType = field.type; @@ -282,7 +284,7 @@ namespace Fig { // assert(argExpr->getType() == Ast::AstType::VarExpr); // argName is var name - const ObjectPtr &argVal = eval(argExpr, ctx); // get the value + const ObjectPtr &argVal = check_unwrap(eval(argExpr, ctx)); // get the value // find field auto fieldIt = std::find_if(structT.fields.begin(), structT.fields.end(), @@ -323,8 +325,8 @@ namespace Fig const Field &field = structT.fields[i]; // evaluate default value in definition context - ObjectPtr defaultVal = eval(field.defaultValue, - defContext); // it can't be null here + ObjectPtr defaultVal = check_unwrap(eval(field.defaultValue, + defContext)); // it can't be null here // type check if (!isTypeMatch(field.type, defaultVal, ctx)) diff --git a/src/Evaluator/Core/EvalLvObject.cpp b/src/Evaluator/Core/EvalLvObject.cpp index 2309e2f..5e3ad6a 100644 --- a/src/Evaluator/Core/EvalLvObject.cpp +++ b/src/Evaluator/Core/EvalLvObject.cpp @@ -1,3 +1,4 @@ +#include "Evaluator/Core/ExprResult.hpp" #include #include #include @@ -5,7 +6,7 @@ namespace Fig { - LvObject Evaluator::evalVarExpr(Ast::VarExpr var, ContextPtr ctx) + ExprResult Evaluator::evalVarExpr(Ast::VarExpr var, ContextPtr ctx) { const FString &name = var->name; @@ -40,10 +41,10 @@ namespace Fig if (!ctx->contains(name)) { throw EvaluatorError(u8"UndeclaredIdentifierError", name, var); } return LvObject(ctx->get(name), ctx); } - LvObject Evaluator::evalMemberExpr(Ast::MemberExpr me, ContextPtr ctx) + ExprResult Evaluator::evalMemberExpr(Ast::MemberExpr me, ContextPtr ctx) { // LvObject base = evalLv(me->base, ctx); - RvObject baseVal = eval(me->base, ctx); + RvObject baseVal = check_unwrap(eval(me->base, ctx)); const FString &member = me->member; if (baseVal->getTypeInfo() == ValueType::Module) { @@ -144,7 +145,7 @@ namespace Fig else if (ctx->hasDefaultImplementedMethod(si.parentType, member)) { const auto &ifm = ctx->getDefaultImplementedMethod(si.parentType, member); - Function fn(member, ifm.paras, actualType(eval(ifm.returnType, ctx)), ifm.defaultBody, ctx); + Function fn(member, ifm.paras, actualType(check_unwrap(eval(ifm.returnType, ctx))), ifm.defaultBody, ctx); return LvObject(std::make_shared( member, std::make_shared(fn), ValueType::Function, AccessModifier::PublicConst), @@ -159,10 +160,10 @@ namespace Fig me->base); } } - LvObject Evaluator::evalIndexExpr(Ast::IndexExpr ie, ContextPtr ctx) + ExprResult Evaluator::evalIndexExpr(Ast::IndexExpr ie, ContextPtr ctx) { - RvObject base = eval(ie->base, ctx); - RvObject index = eval(ie->index, ctx); + RvObject base = check_unwrap(eval(ie->base, ctx)); + RvObject index = check_unwrap(eval(ie->index, ctx)); const TypeInfo &type = base.get()->getTypeInfo(); @@ -215,7 +216,7 @@ namespace Fig ie->base); } } - LvObject Evaluator::evalLv(Ast::Expression exp, ContextPtr ctx) + ExprResult Evaluator::evalLv(Ast::Expression exp, ContextPtr ctx) { using Ast::Operator; using Ast::AstType; diff --git a/src/Evaluator/Core/EvalStatement.cpp b/src/Evaluator/Core/EvalStatement.cpp index 59c81df..6fc34b8 100644 --- a/src/Evaluator/Core/EvalStatement.cpp +++ b/src/Evaluator/Core/EvalStatement.cpp @@ -1,3 +1,4 @@ +#include "Evaluator/Core/ExprResult.hpp" #include #include #include @@ -37,7 +38,7 @@ namespace Fig } RvObject value = nullptr; - if (varDef->expr) { value = eval(varDef->expr, ctx); } + if (varDef->expr) { value = check_unwrap_stres(eval(varDef->expr, ctx)); } TypeInfo declaredType; // default is Any const Ast::Expression &declaredTypeExp = varDef->declaredType; @@ -45,7 +46,7 @@ namespace Fig if (varDef->followupType) { declaredType = actualType(value); } else if (declaredTypeExp) { - ObjectPtr declaredTypeValue = eval(declaredTypeExp, ctx); + ObjectPtr declaredTypeValue = check_unwrap_stres(eval(declaredTypeExp, ctx)); declaredType = actualType(declaredTypeValue); if (value != nullptr && !isTypeMatch(declaredType, value, ctx)) @@ -83,7 +84,7 @@ namespace Fig TypeInfo returnType = ValueType::Any; if (fnDef->retType) { - ObjectPtr returnTypeValue = eval(fnDef->retType, ctx); + ObjectPtr returnTypeValue = check_unwrap_stres(eval(fnDef->retType, ctx)); returnType = actualType(returnTypeValue); } @@ -117,7 +118,10 @@ namespace Fig AccessModifier am = (stDef->isPublic ? AccessModifier::PublicConst : AccessModifier::Const); ctx->def(stDef->name, ValueType::StructType, am, structTypeObj); // predef - defContext->def(stDef->name, ValueType::StructType, AccessModifier::Const, structTypeObj); // predef to itself, always const + defContext->def(stDef->name, + ValueType::StructType, + AccessModifier::Const, + structTypeObj); // predef to itself, always const std::vector fields; std::vector _fieldNames; @@ -134,7 +138,7 @@ namespace Fig TypeInfo fieldType = ValueType::Any; if (field.declaredType) { - ObjectPtr declaredTypeValue = eval(field.declaredType, ctx); + ObjectPtr declaredTypeValue = check_unwrap_stres(eval(field.declaredType, ctx)); fieldType = actualType(declaredTypeValue); } @@ -239,11 +243,10 @@ namespace Fig */ if (ValueType::isTypeBuiltin(structType)) { - throw EvaluatorError( - u8"BadUserError", - std::format("Don't overload built-in type operators plz! `{}`", prettyType(structTypeObj).toBasicString()), - ip - ); + throw EvaluatorError(u8"BadUserError", + std::format("Don't overload built-in type operators plz! `{}`", + prettyType(structTypeObj).toBasicString()), + ip); } using enum Ast::Operator; @@ -328,7 +331,8 @@ namespace Fig const Ast::FunctionParameters ¶s = implMethod.paras; for (size_t i = 0; i < paraCnt; ++i) { - const TypeInfo ¶Type = actualType(eval(paras.posParas[i].second, ctx)); + const TypeInfo ¶Type = + actualType(check_unwrap_stres(eval(paras.posParas[i].second, ctx))); if (paraType != ValueType::Any && paraType != structType) { throw EvaluatorError( @@ -345,7 +349,7 @@ namespace Fig if (paraCnt == 1) { - ctx->registerUnaryOperator(structType, op, [=, this](const ObjectPtr &value) -> ObjectPtr { + ctx->registerUnaryOperator(structType, op, [=, this](const ObjectPtr &value) -> ExprResult { fillOpFnParas({value}); return executeFunction(Function(opFnName, implMethod.paras, // parameters @@ -447,7 +451,7 @@ namespace Fig implemented.insert(name); - ObjectPtr returnTypeValue = eval(ifMethod.returnType, ctx); + ObjectPtr returnTypeValue = check_unwrap_stres(eval(ifMethod.returnType, ctx)); record.implMethods[name] = Function(implMethod.name, implMethod.paras, actualType(returnTypeValue), implMethod.body, ctx); @@ -474,7 +478,7 @@ namespace Fig case IfSt: { auto ifSt = std::static_pointer_cast(stmt); - ObjectPtr condVal = eval(ifSt->condition, ctx); + ObjectPtr condVal = check_unwrap_stres(eval(ifSt->condition, ctx)); if (condVal->getTypeInfo() != ValueType::Bool) { throw EvaluatorError( @@ -486,7 +490,7 @@ namespace Fig // else for (const auto &elif : ifSt->elifs) { - ObjectPtr elifCondVal = eval(elif->condition, ctx); + ObjectPtr elifCondVal = check_unwrap_stres(eval(elif->condition, ctx)); if (elifCondVal->getTypeInfo() != ValueType::Bool) { throw EvaluatorError( @@ -503,7 +507,7 @@ namespace Fig auto whileSt = std::static_pointer_cast(stmt); while (true) { - ObjectPtr condVal = eval(whileSt->condition, ctx); + ObjectPtr condVal = check_unwrap_stres(eval(whileSt->condition, ctx)); if (condVal->getTypeInfo() != ValueType::Bool) { throw EvaluatorError( @@ -535,7 +539,7 @@ namespace Fig while (true) // use while loop to simulate for loop, cause we // need to check condition type every iteration { - ObjectPtr condVal = eval(forSt->condition, loopContext); + ObjectPtr condVal = check_unwrap_stres(eval(forSt->condition, loopContext)); if (condVal->getTypeInfo() != ValueType::Bool) { throw EvaluatorError( @@ -569,10 +573,15 @@ namespace Fig ContextPtr tryCtx = std::make_shared( FString(std::format("", tryst->getAAI().line, tryst->getAAI().column)), ctx); StatementResult sr = StatementResult::normal(); + bool crashed = false; for (auto &stmt : tryst->body->stmts) { sr = evalStatement(stmt, tryCtx); // eval in try context - if (sr.isError()) { break; } + if (sr.isError()) + { + crashed = true; + break; + } } bool catched = false; for (auto &cat : tryst->catches) @@ -591,7 +600,7 @@ namespace Fig break; } } - if (!catched) + if (!catched && crashed) { throw EvaluatorError(u8"UncaughtExceptionError", std::format("Uncaught exception: {}", sr.result->toString().toBasicString()), @@ -604,7 +613,7 @@ namespace Fig case ThrowSt: { auto ts = std::static_pointer_cast(stmt); - ObjectPtr value = eval(ts->value, ctx); + ObjectPtr value = check_unwrap_stres(eval(ts->value, ctx)); if (value->is()) { throw EvaluatorError(u8"TypeError", u8"Why did you throw a null?", ts); @@ -616,7 +625,7 @@ namespace Fig auto returnSt = std::static_pointer_cast(stmt); ObjectPtr returnValue = Object::getNullInstance(); // default is null - if (returnSt->retValue) returnValue = eval(returnSt->retValue, ctx); + if (returnSt->retValue) returnValue = check_unwrap_stres(eval(returnSt->retValue, ctx)); return StatementResult::returnFlow(returnValue); } @@ -646,7 +655,7 @@ namespace Fig case ExpressionStmt: { auto exprStmt = std::static_pointer_cast(stmt); - return StatementResult::normal(eval(exprStmt->exp, ctx)); + return check_unwrap_stres(eval(exprStmt->exp, ctx)); } case BlockStatement: { diff --git a/src/Evaluator/Core/EvalTernary.cpp b/src/Evaluator/Core/EvalTernary.cpp index 6559904..732a485 100644 --- a/src/Evaluator/Core/EvalTernary.cpp +++ b/src/Evaluator/Core/EvalTernary.cpp @@ -1,12 +1,13 @@ #include #include +#include namespace Fig { - RvObject Evaluator::evalTernary(Ast::TernaryExpr te, ContextPtr ctx) + ExprResult Evaluator::evalTernary(Ast::TernaryExpr te, ContextPtr ctx) { - RvObject condVal = eval(te->condition, ctx); + RvObject condVal = check_unwrap(eval(te->condition, ctx)); if (condVal->getTypeInfo() != ValueType::Bool) { throw EvaluatorError( diff --git a/src/Evaluator/Core/EvalUnary.cpp b/src/Evaluator/Core/EvalUnary.cpp index b79dd30..e5f8574 100644 --- a/src/Evaluator/Core/EvalUnary.cpp +++ b/src/Evaluator/Core/EvalUnary.cpp @@ -2,17 +2,18 @@ #include #include #include +#include namespace Fig { - RvObject Evaluator::evalUnary(Ast::UnaryExpr un, ContextPtr ctx) + ExprResult Evaluator::evalUnary(Ast::UnaryExpr un, ContextPtr ctx) { using Ast::Operator; Operator op = un->op; Ast::Expression exp = un->exp; - ObjectPtr value = eval(exp, ctx); + ObjectPtr value = check_unwrap(eval(exp, ctx)); - const auto &tryInvokeOverloadFn = [ctx, op](const ObjectPtr &rhs, const std::function &rollback) { + const auto &tryInvokeOverloadFn = [ctx, op](const ObjectPtr &rhs, const std::function &rollback) { if (rhs->is()) { // 运算符重载 diff --git a/src/Evaluator/Core/ExprResult.cpp b/src/Evaluator/Core/ExprResult.cpp new file mode 100644 index 0000000..53fef3d --- /dev/null +++ b/src/Evaluator/Core/ExprResult.cpp @@ -0,0 +1,19 @@ +#include +#include + +namespace Fig +{ + StatementResult ExprResult::toStatementResult() const + { + if (isError()) + { + if (isResultLv()) + { + return StatementResult::errorFlow(std::get(result).get()); + } + return StatementResult::errorFlow(std::get(result)); + } + if (isResultLv()) { return StatementResult::normal(std::get(result).get()); } + return StatementResult::normal(std::get(result)); + } +}; \ No newline at end of file diff --git a/src/Evaluator/Core/ExprResult.hpp b/src/Evaluator/Core/ExprResult.hpp new file mode 100644 index 0000000..dbcc3d1 --- /dev/null +++ b/src/Evaluator/Core/ExprResult.hpp @@ -0,0 +1,72 @@ +#pragma once + +#include +#include +#include + +#include +#include + +namespace Fig +{ + struct StatementResult; + struct ExprResult + { + std::variant result; + enum class Flow + { + Normal, + Error, + } flow; + + ExprResult(ObjectPtr _result, Flow _flow = Flow::Normal) : result(_result), flow(_flow) {} + ExprResult(const LvObject &_result, Flow _flow = Flow::Normal) : result(_result), flow(_flow) {} + + static ExprResult normal(ObjectPtr _result) { return ExprResult(_result); } + static ExprResult normal(const LvObject &_result) { return ExprResult(_result); } + + static ExprResult error(ObjectPtr _result) { return ExprResult(_result, Flow::Error); } + static ExprResult error(const LvObject &_result) { return ExprResult(_result, Flow::Error); } + + bool isNormal() const { return flow == Flow::Normal; } + + bool isError() const { return flow == Flow::Error; } + + bool isResultLv() const { return std::holds_alternative(result); } + + ObjectPtr &unwrap() + { + if (!isNormal()) { assert(false && "unwrap abnormal ExprResult!"); } + return std::get(result); + } + + const ObjectPtr &unwrap() const + { + if (!isNormal()) { assert(false && "unwrap abnormal ExprResult!"); } + return std::get(result); + } + + const LvObject &unwrap_lv() const { return std::get(result); } + + StatementResult toStatementResult() const; + }; +#define check_unwrap(expr) \ + ({ \ + auto _r = (expr); \ + if (_r.isError()) return _r; \ + _r.unwrap(); \ + }) +#define check_unwrap_lv(expr) \ + ({ \ + auto _r = (expr); \ + if (_r.isError()) return _r; \ + _r.unwrap_lv(); \ + }) +#define check_unwrap_stres(expr) \ + ({ \ + auto _r = (expr); \ + if (_r.isError()) return _r.toStatementResult(); \ + _r.unwrap(); \ + }) + +}; // namespace Fig \ No newline at end of file diff --git a/src/Evaluator/Value/value.hpp b/src/Evaluator/Value/value.hpp index 80c6b73..0258d7b 100644 --- a/src/Evaluator/Value/value.hpp +++ b/src/Evaluator/Value/value.hpp @@ -10,7 +10,7 @@ #include #include -#include +// #include #include #include #include @@ -37,6 +37,11 @@ namespace Fig return d > intMaxAsDouble || d < intMinAsDouble; } + inline bool nearlyEqual(ValueType::DoubleClass l, ValueType::DoubleClass r, ValueType::DoubleClass epsilon = 1e-9) + { + return std::abs(l - r) < epsilon; + } + TypeInfo actualType(std::shared_ptr obj); FString prettyType(std::shared_ptr obj); @@ -646,7 +651,13 @@ namespace Fig } // comparison - friend bool operator==(const Object &lhs, const Object &rhs) { return lhs.data == rhs.data; } + friend bool operator==(const Object &lhs, const Object &rhs) { + if (lhs.isNumeric() && rhs.isNumeric()) + { + return nearlyEqual(lhs.getNumericValue(), rhs.getNumericValue()); + } + return lhs.data == rhs.data; + } friend bool operator!=(const Object &lhs, const Object &rhs) { return !(lhs == rhs); } friend bool operator<(const Object &lhs, const Object &rhs) { diff --git a/src/Evaluator/evaluator.cpp b/src/Evaluator/evaluator.cpp index 234adce..9e4f2b9 100644 --- a/src/Evaluator/evaluator.cpp +++ b/src/Evaluator/evaluator.cpp @@ -1,10 +1,18 @@ +#include "Ast/Expressions/PostfixExprs.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include -#include -#include - +#include #include #include @@ -13,6 +21,9 @@ #include #include +#include +#include + #ifndef SourceInfo #define SourceInfo(ptr) (ptr->sourcePath), (ptr->sourceLines) #endif @@ -50,7 +61,7 @@ namespace Fig std::vector modSourceLines; - if (mod_ast_cache.contains(modSourcePath)) + if (mod_ast_cache.contains(modSourcePath)) { auto &[_sl, _asts] = mod_ast_cache[modSourcePath]; modSourceLines = _sl; @@ -87,15 +98,25 @@ namespace Fig { const std::vector &pathVec = i->path; - const FString &modName = pathVec.at(pathVec.size() - 1); // pathVec at least has 1 element + FString modName = pathVec.back(); // pathVec at least has 1 element if (modName == u8"_builtins") { RegisterBuiltins(); return StatementResult::normal(); } + + // std::cerr << modName.toBasicString() << '\n'; DEBUG + + if (ctx->containsInThisScope(modName)) + { + throw EvaluatorError( + u8"RedeclarationError", std::format("{} has already been declared.", modName.toBasicString()), i); + } + auto path = resolveModulePath(pathVec); ContextPtr modCtx = loadModule(path); + // 冲突问题等impl存储改成 2xMap之后解决吧(咕咕咕 ctx->getImplRegistry().insert(modCtx->getImplRegistry().begin(), modCtx->getImplRegistry().end()); // load impl for (auto &[type, opRecord] : modCtx->getOpRegistry()) @@ -112,16 +133,21 @@ namespace Fig } ctx->getOpRegistry()[type] = opRecord; } - - // std::cerr << modName.toBasicString() << '\n'; DEBUG - - if (ctx->containsInThisScope(modName)) + if (!i->names.empty()) { - throw EvaluatorError( - u8"RedeclarationError", std::format("{} has already been declared.", modName.toBasicString()), i); + for (const FString &symName : i->names) + { + LvObject tmp(modCtx->get(symName), modCtx); + const ObjectPtr &value = tmp.get(); + + ctx->def(symName, tmp.declaredType(), AccessModifier::Const, value); + } + return StatementResult::normal(); } + if (!i->rename.empty()) { modName = i->rename; } ctx->def( modName, ValueType::Module, AccessModifier::PublicConst, std::make_shared(Module(modName, modCtx))); + return StatementResult::normal(); } @@ -131,30 +157,73 @@ namespace Fig StatementResult sr = StatementResult::normal(); for (auto &ast : asts) { - Ast::Expression exp; - if ((exp = std::dynamic_pointer_cast(ast))) // 保持 dynamic_pointer_cast ! - { - sr = StatementResult::normal(eval(exp, global)); - } - else - { - // statement - Ast::Statement stmt = std::static_pointer_cast(ast); - assert(stmt != nullptr); - sr = evalStatement(stmt, global); - if (sr.isError()) - { - throw EvaluatorError(u8"UncaughtExceptionError", - std::format("Uncaught exception: {}", sr.result->toString().toBasicString()), - stmt); - } - if (!sr.isNormal()) { return sr; } - } + // statement, all stmt! + Ast::Statement stmt = std::static_pointer_cast(ast); + assert(stmt != nullptr); + sr = evalStatement(stmt, global); + if (sr.isError()) { handle_error(sr, stmt, global); } + if (!sr.isNormal()) { return sr; } } return sr; } + void Evaluator::handle_error(const StatementResult &sr, const Ast::Statement &stmt, const ContextPtr &ctx) + { + assert(sr.isError()); + const ObjectPtr &result = sr.result; + const TypeInfo &resultType = actualType(result); + + if (result->is() && implements(resultType, Builtins::getErrorInterfaceTypeInfo(), ctx)) + { + /* + toString() -> String + getErrorClass() -> String + getErrorMessage() -> String + */ + const StructInstance &resInst = result->as(); + + Function getErrorClassFn = ctx->getImplementedMethod(resultType, u8"getErrorClass"); + getErrorClassFn = Function(getErrorClassFn.name, + getErrorClassFn.paras, + getErrorClassFn.retType, + getErrorClassFn.body, + resInst.localContext); + Function getErrorMessageFn = ctx->getImplementedMethod(resultType, u8"getErrorMessage"); + getErrorMessageFn = Function(getErrorMessageFn.name, + getErrorMessageFn.paras, + getErrorMessageFn.retType, + getErrorMessageFn.body, + resInst.localContext); + + const ExprResult &errorClassRes = + executeFunction(getErrorClassFn, Ast::FunctionCallArgs{}, resInst.localContext); + const ExprResult &errorMessageRes = + executeFunction(getErrorMessageFn, Ast::FunctionCallArgs{}, resInst.localContext); + + if (errorClassRes.isError()) { handle_error(errorClassRes.toStatementResult(), getErrorClassFn.body, ctx); } + if (errorMessageRes.isError()) + { + handle_error(errorMessageRes.toStatementResult(), getErrorMessageFn.body, ctx); + } + + // std::cerr << errorClassRes.unwrap()->toString().toBasicString() << "\n"; + // std::cerr << errorMessageRes.unwrap()->toString().toBasicString() << "\n"; + + const FString &errorClass = errorClassRes.unwrap()->as(); + const FString &errorMessage = errorMessageRes.unwrap()->as(); + + ErrorLog::logFigErrorInterface(errorClass, errorMessage); + std::exit(1); + } + else + { + throw EvaluatorError(u8"UncaughtExceptionError", + std::format("Uncaught exception: {}", sr.result->toString().toBasicString()), + stmt); + } + } + void Evaluator::printStackTrace() { if (global) global->printStackTrace(); diff --git a/src/Evaluator/evaluator.hpp b/src/Evaluator/evaluator.hpp index b982fc4..c141aa9 100644 --- a/src/Evaluator/evaluator.hpp +++ b/src/Evaluator/evaluator.hpp @@ -1,4 +1,12 @@ #pragma once +#include "Ast/AccessModifier.hpp" +#include "Ast/Expressions/BinaryExpr.hpp" +#include "Ast/Expressions/ValueExpr.hpp" +#include "Ast/Expressions/VarExpr.hpp" +#include "Ast/Statements/ControlSt.hpp" +#include "Ast/astBase.hpp" +#include "Ast/functionParameters.hpp" +#include "Value/value.hpp" #include #include #include @@ -10,9 +18,13 @@ #include #include #include +#include #include #include +#include +#include +#include namespace Fig { @@ -47,6 +59,43 @@ namespace Fig Function f(name, fn, argc); global->def(name, ValueType::Function, AccessModifier::Const, std::make_shared(f)); } + + global->setImplRecord( + Builtins::getTypeErrorStructTypeInfo(), + Builtins::getErrorInterfaceTypeInfo(), + ImplRecord{ + .interfaceType = Builtins::getErrorInterfaceTypeInfo(), + .structType = Builtins::getTypeErrorStructTypeInfo(), + .implMethods = { + {u8"toString", + Function( + u8"toString", + Ast::FunctionParameters{}, + ValueType::String, + std::make_shared(std::vector( + {std::make_shared(std::make_shared( + std::make_shared(std::make_shared(u8"TypeError: ")), + Ast::Operator::Add, + std::make_shared( + std::make_shared(u8"getErrorMessage"), + Ast::FunctionArguments{})))})), + nullptr)}, + {u8"getErrorClass", + Function(u8"getErrorClass", + Ast::FunctionParameters{}, + ValueType::String, + std::make_shared(std::vector( + {std::make_shared(std::make_shared( + std::make_shared(FString(u8"TypeError"))))})), + nullptr)}, + {u8"getErrorMessage", + Function(u8"getErrorMessage", + Ast::FunctionParameters{}, + ValueType::String, + std::make_shared(std::vector( + {std::make_shared(std::make_shared(u8"msg"))})), + nullptr)}, + }}); } void RegisterBuiltinsValue() @@ -61,25 +110,35 @@ namespace Fig bool isInterfaceSignatureMatch(const Ast::ImplementMethod &, const Ast::InterfaceMethod &); - /* Left-value eval*/ - LvObject evalVarExpr(Ast::VarExpr, ContextPtr); - LvObject evalMemberExpr(Ast::MemberExpr, ContextPtr); // a.b - LvObject evalIndexExpr(Ast::IndexExpr, ContextPtr); // a[b] + ObjectPtr genTypeError(const FString &_msg, + const Ast::AstBase &_ast, + ContextPtr ctx, + std::source_location loc = std::source_location::current()) + { + ContextPtr stCtx = std::make_shared(u8""); + stCtx->def(u8"msg", ValueType::String, AccessModifier::Const, std::make_shared(_msg)); + return std::make_shared(StructInstance(Builtins::getTypeErrorStructTypeInfo(), stCtx)); + } - LvObject evalLv(Ast::Expression, ContextPtr); // for access: a.b / index a[b] + /* Left-value eval*/ + ExprResult evalVarExpr(Ast::VarExpr, ContextPtr); // identifier: a, b, c + ExprResult evalMemberExpr(Ast::MemberExpr, ContextPtr); // a.b + ExprResult evalIndexExpr(Ast::IndexExpr, ContextPtr); // a[b] + + ExprResult evalLv(Ast::Expression, ContextPtr); // for access: a.b / index a[b] /* Right-value eval*/ - RvObject evalInitExpr(Ast::InitExpr, ContextPtr); // only allows evalUnary to call - RvObject evalBinary(Ast::BinaryExpr, ContextPtr); // normal binary expr: +, -, *.... - RvObject evalUnary(Ast::UnaryExpr, ContextPtr); // unary expr - RvObject evalTernary(Ast::TernaryExpr, ContextPtr); // ternary expr + ExprResult evalInitExpr(Ast::InitExpr, ContextPtr); + ExprResult evalBinary(Ast::BinaryExpr, ContextPtr); // normal binary expr: +, -, *.... + ExprResult evalUnary(Ast::UnaryExpr, ContextPtr); // unary expr + ExprResult evalTernary(Ast::TernaryExpr, ContextPtr); // ternary expr - RvObject executeFunction(const Function &fn, const Ast::FunctionCallArgs &, ContextPtr); // fn, fn context + ExprResult executeFunction(const Function &fn, const Ast::FunctionCallArgs &, ContextPtr); // fn, fn context - RvObject evalFunctionCall(const Ast::FunctionCall &, - ContextPtr); // function call + ExprResult evalFunctionCall(const Ast::FunctionCall &, + ContextPtr); // function call - RvObject eval(Ast::Expression, ContextPtr); + ExprResult eval(Ast::Expression, ContextPtr); StatementResult evalBlockStatement(Ast::BlockStatement, ContextPtr); // block StatementResult evalStatement(Ast::Statement, ContextPtr); // statement @@ -91,6 +150,8 @@ namespace Fig StatementResult Run(std::vector); // Entry + void handle_error(const StatementResult &, const Ast::Statement &, const ContextPtr &); + void printStackTrace(); }; }; // namespace Fig \ No newline at end of file diff --git a/src/Lexer/lexer.cpp b/src/Lexer/lexer.cpp index db4cd3f..0b95eab 100644 --- a/src/Lexer/lexer.cpp +++ b/src/Lexer/lexer.cpp @@ -97,6 +97,7 @@ namespace Fig {FString(u8"catch"), TokenType::Catch}, {FString(u8"throw"), TokenType::Throw}, {FString(u8"Finally"), TokenType::Finally}, + {FString(u8"as"), TokenType::As}, // {FString(u8"Null"), TokenType::TypeNull}, // {FString(u8"Int"), TokenType::TypeInt}, diff --git a/src/Module/Library/lang/lang.fig b/src/Module/Library/lang/lang.fig index 33575bf..f89e4bb 100644 --- a/src/Module/Library/lang/lang.fig +++ b/src/Module/Library/lang/lang.fig @@ -31,6 +31,27 @@ public interface Error getErrorMessage() -> String; } +public struct TypeError +{ + public msg: String; +} + +impl Error for TypeError +{ + toString() + { + return "TypeError: " + getErrorMessage(); + } + getErrorClass() + { + return "TypeError"; + } + getErrorMessage() + { + return msg; + } +} + // Operation interface public interface Operation diff --git a/src/Module/Library/std/std.fig b/src/Module/Library/std/std.fig index 571cff5..2a59f2b 100644 --- a/src/Module/Library/std/std.fig +++ b/src/Module/Library/std/std.fig @@ -3,7 +3,12 @@ Library/std/std.fig */ -import io; // link std.io -import value; // link std.type -import math; // link std.math -import tester; // link std.tester \ No newline at end of file +import io as std_io; +import value as std_value; +import math as std_math; +import test as std_test; + +public const io := std_io; // link std.io +public const value := std_value; // link std.type +public const math := std_math; // link std.math +public const test := std_test; // link std.test \ No newline at end of file diff --git a/src/Module/builtins.cpp b/src/Module/builtins.cpp index a524e0b..95541ea 100644 --- a/src/Module/builtins.cpp +++ b/src/Module/builtins.cpp @@ -1,13 +1,42 @@ +#include "Ast/Expressions/BinaryExpr.hpp" +#include "Ast/Expressions/FunctionCall.hpp" +#include "Ast/Expressions/ValueExpr.hpp" +#include "Ast/Expressions/VarExpr.hpp" +#include "Ast/Statements/ControlSt.hpp" +#include "Ast/astBase.hpp" +#include "Ast/functionParameters.hpp" +#include +#include +#include +#include +#include #include +#include #include #include #include #include #include +#include namespace Fig::Builtins { + const TypeInfo &getErrorInterfaceTypeInfo() + { + static const TypeInfo ErrorInterfaceTypeInfo(u8"Error", true); + return ErrorInterfaceTypeInfo; + } + const TypeInfo &getTypeErrorStructTypeInfo() + { + static const TypeInfo TypeErrorStructTypeInfo(u8"TypeError", true); + return TypeErrorStructTypeInfo; + } + const TypeInfo &getOperationInterfaceTypeInfo() + { + static const TypeInfo OperationInterfaceTypeInfo(u8"Operation", true); + return OperationInterfaceTypeInfo; + } const std::unordered_map &getBuiltinValues() { static const std::unordered_map builtinValues = { @@ -28,7 +57,12 @@ namespace Fig::Builtins Ast::FunctionParameters({}, {}), std::make_shared(u8"String"), nullptr)}))}, - {u8"Operation", std::make_shared(InterfaceType(getOperationInterfaceTypeInfo(), {}))}, + {u8"TypeError", std::make_shared(StructType( + getTypeErrorStructTypeInfo(), + std::make_shared(u8""), + {Field(AccessModifier::Public, u8"msg", ValueType::String, nullptr)} + ))}, + {u8"Operation", std::make_shared(InterfaceType(getOperationInterfaceTypeInfo(), {}))}, {u8"Any", std::make_shared(StructType(ValueType::Any, nullptr, {}, true))}, {u8"Int", std::make_shared(StructType(ValueType::Int, nullptr, {}, true))}, @@ -119,8 +153,8 @@ namespace Fig::Builtins }}, {u8"__fvalue_type", [](const std::vector &args) -> ObjectPtr { - return std::make_shared(args[0]->getTypeInfo().toString()); - }}, + return std::make_shared(args[0]->getTypeInfo().toString()); + }}, {u8"__fvalue_int_parse", [](const std::vector &args) -> ObjectPtr { FString str = args[0]->as(); @@ -380,4 +414,4 @@ namespace Fig::Builtins }; return builtinFunctions; } -} \ No newline at end of file +} // namespace Fig::Builtins \ No newline at end of file diff --git a/src/Module/builtins.hpp b/src/Module/builtins.hpp index e8035cf..86b3d26 100644 --- a/src/Module/builtins.hpp +++ b/src/Module/builtins.hpp @@ -26,12 +26,9 @@ namespace Fig } */ - inline static const TypeInfo &getErrorInterfaceTypeInfo() - { - static const TypeInfo ErrorInterfaceTypeInfo(u8"Error", true); - return ErrorInterfaceTypeInfo; - } + const TypeInfo &getErrorInterfaceTypeInfo(); + const TypeInfo &getTypeErrorStructTypeInfo(); /* interface Operation { @@ -40,11 +37,7 @@ namespace Fig */ - inline static const TypeInfo &getOperationInterfaceTypeInfo() - { - static const TypeInfo OperationInterfaceTypeInfo(u8"Operation", true); - return OperationInterfaceTypeInfo; - } + const TypeInfo &getOperationInterfaceTypeInfo(); const std::unordered_map &getBuiltinValues(); diff --git a/src/Parser/parser.cpp b/src/Parser/parser.cpp index 5134bd9..88e9321 100644 --- a/src/Parser/parser.cpp +++ b/src/Parser/parser.cpp @@ -49,6 +49,9 @@ namespace Fig {Ast::Operator::GreaterEqual, {100, 101}}, {Ast::Operator::Is, {100, 101}}, + // 转换 + {Ast::Operator::As, {105, 106}}, + // 位移 {Ast::Operator::ShiftLeft, {110, 111}}, {Ast::Operator::ShiftRight, {110, 111}}, @@ -998,6 +1001,8 @@ namespace Fig { next(); // consume `import` std::vector path; + std::vector names; + FString rename; while (true) { expect(TokenType::Identifier, u8"package name"); @@ -1008,13 +1013,41 @@ namespace Fig { next(); // consume `.` } + else if (isThis(TokenType::As)) { break; } + else if (isThis(TokenType::LeftBrace)) { break; } else { - throw SyntaxError(); + throwAddressableError(u8"invalid syntax"); + } + } + if (isThis(TokenType::As)) + { + next(); // consume `as` + expect(TokenType::Identifier, u8"new name"); + rename = currentToken().getValue(); + next(); // consume name + } + else if (isThis(TokenType::LeftBrace)) + { + next(); // consume `{` + while (true) + { + if (isThis(TokenType::RightBrace)) + { + next(); // consume `}` + break; + } + if (isThis(TokenType::Comma)) + { + next(); // consume `,` + } + expect(TokenType::Identifier, u8"symbol name"); + names.push_back(currentToken().getValue()); + next(); } } expectSemicolon(); - return makeAst(path); + return makeAst(path, names, rename); } Ast::Expression Parser::parseExpression(Precedence bp, TokenType stop, TokenType stop2, TokenType stop3) diff --git a/src/Token/token.hpp b/src/Token/token.hpp index 575d460..acd690e 100644 --- a/src/Token/token.hpp +++ b/src/Token/token.hpp @@ -44,6 +44,7 @@ namespace Fig Catch, // catch Throw, // throw Finally, // finally + As, // as // TypeNull, // Null // TypeInt, // Int