挺大的改动。增加 as运算符,转换不了抛出 TypeError。import语法更新。修复try一点错误。现在表达式运算返回ExprResult。通过3个宏实现简便错误传播与解包 unwrap

This commit is contained in:
2026-02-04 18:14:30 +08:00
parent 27cf09cad0
commit b98c1b7dd8
26 changed files with 693 additions and 206 deletions

View File

@@ -16,6 +16,7 @@
#include <Core/fig_string.hpp>
#include <Evaluator/Value/value.hpp>
#include <Evaluator/Value/VariableSlot.hpp>
#include <Evaluator/Core/ExprResult.hpp>
namespace Fig
{
@@ -30,8 +31,8 @@ namespace Fig
struct OperationRecord
{
using UnaryOpFn = std::function<ObjectPtr(const ObjectPtr &)>;
using BinaryOpFn = std::function<ObjectPtr(const ObjectPtr &, const ObjectPtr &)>;
using UnaryOpFn = std::function<ExprResult(const ObjectPtr &)>;
using BinaryOpFn = std::function<ExprResult(const ObjectPtr &, const ObjectPtr &)>;
std::unordered_map<Ast::Operator, UnaryOpFn> unOpRec;
std::unordered_map<Ast::Operator, BinaryOpFn> binOpRec;

View File

@@ -1,9 +1,10 @@
#include <Evaluator/evaluator.hpp>
#include <Evaluator/evaluator_error.hpp>
#include <Evaluator/Core/ExprResult.hpp>
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<Ast::VarExprAst>(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<Ast::BinaryExprAst>(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<Ast::FunctionCallExpr>(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<Object>(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<Object>(std::move(map));
}

View File

@@ -1,23 +1,27 @@
#include <Ast/Expressions/BinaryExpr.hpp>
#include <Evaluator/Value/value.hpp>
#include <Evaluator/Value/Type.hpp>
#include <Evaluator/Value/Type.hpp>
#include <Evaluator/Value/LvObject.hpp>
#include <Evaluator/Value/IntPool.hpp>
#include <Evaluator/evaluator.hpp>
#include <Evaluator/evaluator_error.hpp>
#include <Evaluator/Core/ExprResult.hpp>
#include <exception>
#include <memory>
#include <functional>
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<ObjectPtr()> &rollback) {
[ctx, op](const ObjectPtr &lhs, const ObjectPtr &rhs, const std::function<ExprResult()> &rollback) {
if (lhs->is<StructInstance>() && 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<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
{
@@ -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<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
{
@@ -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<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
{
@@ -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<Object>(*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<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
{
@@ -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<StructType>())
{
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<StructType>();
const TypeInfo &targetType = targetStructType.type;
const TypeInfo &sourceType = lhs->getTypeInfo();
if (targetType == sourceType) { return lhs; }
if (targetType == ValueType::String) { return std::make_shared<Object>(lhs->toStringIO()); }
if (sourceType == ValueType::Int)
{
if (targetType == ValueType::Double)
{
return std::make_shared<Object>(
static_cast<ValueType::DoubleClass>(lhs->as<ValueType::IntClass>()));
}
}
else if (sourceType == ValueType::Double)
{
if (targetType == ValueType::Int)
{
return IntPool::getInstance().createInt(
static_cast<ValueType::IntClass>(lhs->as<ValueType::DoubleClass>()));
}
}
else if (sourceType == ValueType::String)
{
const FString &str = lhs->as<ValueType::StringClass>();
if (targetType == ValueType::Int)
{
try
{
return IntPool::getInstance().createInt(
static_cast<ValueType::IntClass>(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<Object>(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<ValueType::IntClass>(lhs->as<ValueType::BoolClass>()));
}
if (targetType == ValueType::Double)
{
return std::make_shared<Object>(static_cast<ValueType::DoubleClass>(lhs->as<ValueType::BoolClass>()));
}
}
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<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
@@ -156,9 +265,10 @@ namespace Fig
return std::make_shared<Object>(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<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
@@ -169,9 +279,10 @@ namespace Fig
return std::make_shared<Object>(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<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
@@ -182,9 +293,10 @@ namespace Fig
return std::make_shared<Object>(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<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
@@ -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<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
@@ -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<bool>() && !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<Object>(*lhs && *rhs); });
}
case Operator::Or: {
ObjectPtr lhs = eval(lexp, ctx);
ObjectPtr lhs = check_unwrap(eval(lexp, ctx));
if (lhs->is<bool>() && 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<Object>(*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<Object>(*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<Object>(*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<Object>(*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<Object>(*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<Object>(*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<Object>(*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<Object>(*lhs + *rhs); });
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
const ObjectPtr &result = check_unwrap(
tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*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<Object>(*lhs - *rhs); });
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
const ObjectPtr &result = check_unwrap(
tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*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<Object>(*lhs * *rhs); });
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
const ObjectPtr &result = check_unwrap(
tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*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<Object>(*lhs / *rhs); });
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
const ObjectPtr &result = check_unwrap(
tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*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<Object>(*lhs % *rhs); });
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
const ObjectPtr &result = check_unwrap(
tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs % *rhs); }));
lv.set(result);
return rhs;
}
default:
throw EvaluatorError(u8"UnsupportedOp",
std::format("Unsupport operator '{}' for binary", magic_enum::enum_name(op)),

View File

@@ -5,10 +5,11 @@
#include <Evaluator/Value/LvObject.hpp>
#include <Evaluator/evaluator.hpp>
#include <Evaluator/evaluator_error.hpp>
#include <Evaluator/Core/ExprResult.hpp>
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<Object>(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))
{

View File

@@ -1,3 +1,4 @@
#include <Evaluator/Core/ExprResult.hpp>
#include <Evaluator/Value/value.hpp>
#include <Evaluator/Value/LvObject.hpp>
#include <Evaluator/evaluator.hpp>
@@ -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<StructType>())
@@ -46,7 +47,7 @@ namespace Fig
return std::make_shared<Object>(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<std::pair<FString, ObjectPtr>> 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))

View File

@@ -1,3 +1,4 @@
#include "Evaluator/Core/ExprResult.hpp"
#include <Evaluator/Value/value.hpp>
#include <Evaluator/Value/LvObject.hpp>
#include <Evaluator/evaluator.hpp>
@@ -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<VariableSlot>(
member, std::make_shared<Object>(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;

View File

@@ -1,3 +1,4 @@
#include "Evaluator/Core/ExprResult.hpp"
#include <Ast/AccessModifier.hpp>
#include <Ast/Expressions/FunctionCall.hpp>
#include <Ast/astBase.hpp>
@@ -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<Field> fields;
std::vector<FString> _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 &paras = implMethod.paras;
for (size_t i = 0; i < paraCnt; ++i)
{
const TypeInfo &paraType = actualType(eval(paras.posParas[i].second, ctx));
const TypeInfo &paraType =
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<Ast::IfSt>(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<Ast::WhileSt>(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<Context>(
FString(std::format("<Try at {}:{}>", 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<Ast::ThrowSt>(stmt);
ObjectPtr value = eval(ts->value, ctx);
ObjectPtr value = check_unwrap_stres(eval(ts->value, ctx));
if (value->is<ValueType::NullClass>())
{
throw EvaluatorError(u8"TypeError", u8"Why did you throw a null?", ts);
@@ -616,7 +625,7 @@ namespace Fig
auto returnSt = std::static_pointer_cast<Ast::ReturnSt>(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<Ast::ExpressionStmtAst>(stmt);
return StatementResult::normal(eval(exprStmt->exp, ctx));
return check_unwrap_stres(eval(exprStmt->exp, ctx));
}
case BlockStatement: {

View File

@@ -1,12 +1,13 @@
#include <Evaluator/evaluator.hpp>
#include <Evaluator/evaluator_error.hpp>
#include <Evaluator/Core/ExprResult.hpp>
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(

View File

@@ -2,17 +2,18 @@
#include <Evaluator/Value/LvObject.hpp>
#include <Evaluator/evaluator.hpp>
#include <Evaluator/evaluator_error.hpp>
#include <Evaluator/Core/ExprResult.hpp>
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<ObjectPtr()> &rollback) {
const auto &tryInvokeOverloadFn = [ctx, op](const ObjectPtr &rhs, const std::function<ExprResult()> &rollback) {
if (rhs->is<StructInstance>())
{
// 运算符重载

View File

@@ -0,0 +1,19 @@
#include <Evaluator/Core/ExprResult.hpp>
#include <Evaluator/Core/StatementResult.hpp>
namespace Fig
{
StatementResult ExprResult::toStatementResult() const
{
if (isError())
{
if (isResultLv())
{
return StatementResult::errorFlow(std::get<LvObject>(result).get());
}
return StatementResult::errorFlow(std::get<RvObject>(result));
}
if (isResultLv()) { return StatementResult::normal(std::get<LvObject>(result).get()); }
return StatementResult::normal(std::get<RvObject>(result));
}
};

View File

@@ -0,0 +1,72 @@
#pragma once
#include <Core/fig_string.hpp>
#include <Evaluator/Value/value_forward.hpp>
#include <Evaluator/Value/LvObject.hpp>
#include <variant>
#include <cassert>
namespace Fig
{
struct StatementResult;
struct ExprResult
{
std::variant<LvObject, RvObject> 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<LvObject>(result); }
ObjectPtr &unwrap()
{
if (!isNormal()) { assert(false && "unwrap abnormal ExprResult!"); }
return std::get<RvObject>(result);
}
const ObjectPtr &unwrap() const
{
if (!isNormal()) { assert(false && "unwrap abnormal ExprResult!"); }
return std::get<RvObject>(result);
}
const LvObject &unwrap_lv() const { return std::get<LvObject>(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

View File

@@ -10,7 +10,7 @@
#include <Evaluator/Value/value_forward.hpp>
#include <cassert>
#include <iostream>
// #include <iostream>
#include <memory>
#include <unordered_set>
#include <variant>
@@ -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<const Object> obj);
FString prettyType(std::shared_ptr<const Object> 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)
{

View File

@@ -1,10 +1,18 @@
#include "Ast/Expressions/PostfixExprs.hpp"
#include <Ast/AccessModifier.hpp>
#include <Ast/Expressions/FunctionCall.hpp>
#include <Evaluator/Context/context.hpp>
#include <Evaluator/Core/ExprResult.hpp>
#include <Evaluator/Value/value.hpp>
#include <Module/builtins.hpp>
#include <Evaluator/Value/LvObject.hpp>
#include <Evaluator/Value/Type.hpp>
#include <Evaluator/Value/structInstance.hpp>
#include <Ast/astBase.hpp>
#include <Core/fig_string.hpp>
#include <Evaluator/Core/StatementResult.hpp>
#include <Evaluator/Value/value.hpp>
#include <Utils/utils.hpp>
#include <Parser/parser.hpp>
#include <Error/errorLog.hpp>
#include <Evaluator/evaluator.hpp>
#include <Evaluator/evaluator_error.hpp>
@@ -13,6 +21,9 @@
#include <memory>
#include <unordered_map>
#include <Utils/utils.hpp>
#include <Parser/parser.hpp>
#ifndef SourceInfo
#define SourceInfo(ptr) (ptr->sourcePath), (ptr->sourceLines)
#endif
@@ -50,7 +61,7 @@ namespace Fig
std::vector<FString> 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<FString> &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<Object>(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::ExpressionAst>(ast))) // 保持 dynamic_pointer_cast !
{
sr = StatementResult::normal(eval(exp, global));
}
else
{
// statement
Ast::Statement stmt = std::static_pointer_cast<Ast::StatementAst>(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::StatementAst>(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<StructInstance>() && implements(resultType, Builtins::getErrorInterfaceTypeInfo(), ctx))
{
/*
toString() -> String
getErrorClass() -> String
getErrorMessage() -> String
*/
const StructInstance &resInst = result->as<StructInstance>();
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<ValueType::StringClass>();
const FString &errorMessage = errorMessageRes.unwrap()->as<ValueType::StringClass>();
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();

View File

@@ -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 <Ast/Expressions/FunctionCall.hpp>
#include <Ast/Expressions/InitExpr.hpp>
#include <Ast/Statements/ImplementSt.hpp>
@@ -10,9 +18,13 @@
#include <Error/error.hpp>
#include <Module/builtins.hpp>
#include <Evaluator/Value/LvObject.hpp>
#include <cstddef>
#include <filesystem>
#include <Evaluator/Core/StatementResult.hpp>
#include <Evaluator/Core/ExprResult.hpp>
#include <memory>
#include <source_location>
namespace Fig
{
@@ -47,6 +59,43 @@ namespace Fig
Function f(name, fn, argc);
global->def(name, ValueType::Function, AccessModifier::Const, std::make_shared<Object>(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<Ast::BlockStatementAst>(std::vector<Ast::Statement>(
{std::make_shared<Ast::ReturnSt>(std::make_shared<Ast::BinaryExprAst>(
std::make_shared<Ast::ValueExprAst>(std::make_shared<Object>(u8"TypeError: ")),
Ast::Operator::Add,
std::make_shared<Ast::FunctionCallExpr>(
std::make_shared<Ast::VarExprAst>(u8"getErrorMessage"),
Ast::FunctionArguments{})))})),
nullptr)},
{u8"getErrorClass",
Function(u8"getErrorClass",
Ast::FunctionParameters{},
ValueType::String,
std::make_shared<Ast::BlockStatementAst>(std::vector<Ast::Statement>(
{std::make_shared<Ast::ReturnSt>(std::make_shared<Ast::ValueExprAst>(
std::make_shared<Object>(FString(u8"TypeError"))))})),
nullptr)},
{u8"getErrorMessage",
Function(u8"getErrorMessage",
Ast::FunctionParameters{},
ValueType::String,
std::make_shared<Ast::BlockStatementAst>(std::vector<Ast::Statement>(
{std::make_shared<Ast::ReturnSt>(std::make_shared<Ast::VarExprAst>(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<Context>(u8"<TypeError Instance>");
stCtx->def(u8"msg", ValueType::String, AccessModifier::Const, std::make_shared<Object>(_msg));
return std::make_shared<Object>(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<Ast::AstBase>); // Entry
void handle_error(const StatementResult &, const Ast::Statement &, const ContextPtr &);
void printStackTrace();
};
}; // namespace Fig