forked from PuqiAR/Fig-TreeWalker
[Feat] 支持运算符重载!详见文档或 Library/lang/lang.fig中的定义。通过 impl Operation for xxx实现重载
[Impl] 函数参数指定现在也接受一个 exp,逐渐改动其他中...
This commit is contained in:
@@ -39,27 +39,7 @@ namespace Fig
|
||||
|
||||
case AstType::FunctionCall: {
|
||||
auto fnCall = std::static_pointer_cast<Ast::FunctionCallExpr>(exp);
|
||||
|
||||
Ast::Expression callee = fnCall->callee;
|
||||
ObjectPtr fnObj = eval(callee, ctx);
|
||||
if (fnObj->getTypeInfo() != ValueType::Function)
|
||||
{
|
||||
throw EvaluatorError(u8"ObjectNotCallable",
|
||||
std::format("Object `{}` isn't callable", fnObj->toString().toBasicString()),
|
||||
callee);
|
||||
}
|
||||
const Function &fn = fnObj->as<Function>();
|
||||
size_t fnId = fn.id;
|
||||
// const auto &fnNameOpt = ctx->getFunctionName(fnId);
|
||||
// const FString &fnName = (fnNameOpt ? *fnNameOpt :
|
||||
// u8"<anonymous>");
|
||||
|
||||
auto fnNameOpt = ctx->getFunctionName(fnId);
|
||||
if (!fnNameOpt && fn.closureContext) fnNameOpt = fn.closureContext->getFunctionName(fnId);
|
||||
|
||||
const FString &fnName = (fnNameOpt ? *fnNameOpt : u8"<anonymous> or builtin-type member function");
|
||||
|
||||
return evalFunctionCall(fn, fnCall->arg, fnName, ctx);
|
||||
return evalFunctionCall(fnCall, ctx);
|
||||
}
|
||||
case AstType::FunctionLiteralExpr: {
|
||||
auto fnLiteral = std::static_pointer_cast<Ast::FunctionLiteralExprAst>(exp);
|
||||
@@ -84,7 +64,7 @@ namespace Fig
|
||||
body = fnLiteral->getBlockBody();
|
||||
|
||||
}
|
||||
Function fn(fnLiteral->paras, ValueType::Any, body, ctx
|
||||
Function fn(FString(std::format("<LambdaFn>")),fnLiteral->paras, ValueType::Any, body, ctx
|
||||
/*
|
||||
pass the ctx(fnLiteral eval context) as closure context
|
||||
*/
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
#include "Ast/Expressions/BinaryExpr.hpp"
|
||||
#include <Evaluator/Value/value.hpp>
|
||||
#include <Evaluator/Value/LvObject.hpp>
|
||||
#include <Evaluator/Value/IntPool.hpp>
|
||||
#include <Evaluator/evaluator.hpp>
|
||||
#include <Evaluator/evaluator_error.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
RvObject Evaluator::evalBinary(Ast::BinaryExpr bin, ContextPtr ctx)
|
||||
@@ -11,229 +15,198 @@ namespace Fig
|
||||
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) {
|
||||
if (lhs->is<StructInstance>() && lhs->getTypeInfo() == rhs->getTypeInfo())
|
||||
{
|
||||
// 运算符重载
|
||||
const TypeInfo &type = actualType(lhs);
|
||||
if (ctx->hasOperatorImplemented(type, op))
|
||||
{
|
||||
const auto &fnOpt = ctx->getBinaryOperatorFn(type, op);
|
||||
return (*fnOpt)(lhs, rhs);
|
||||
}
|
||||
}
|
||||
return rollback();
|
||||
};
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case Operator::Add: {
|
||||
ObjectPtr lhs = eval(lexp, ctx);
|
||||
ObjectPtr rhs = eval(rexp, ctx);
|
||||
|
||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||
{
|
||||
ValueType::IntClass result = lhs->as<ValueType::IntClass>() + rhs->as<ValueType::IntClass>();
|
||||
return IntPool::getInstance().createInt(result);
|
||||
}
|
||||
|
||||
return std::make_shared<Object>(*lhs + *rhs);
|
||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||
{
|
||||
ValueType::IntClass result = lhs->as<ValueType::IntClass>() + rhs->as<ValueType::IntClass>();
|
||||
return IntPool::getInstance().createInt(result);
|
||||
}
|
||||
return std::make_shared<Object>(*lhs + *rhs);
|
||||
});
|
||||
}
|
||||
case Operator::Subtract: {
|
||||
ObjectPtr lhs = eval(lexp, ctx);
|
||||
ObjectPtr rhs = eval(rexp, ctx);
|
||||
|
||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||
{
|
||||
ValueType::IntClass result = lhs->as<ValueType::IntClass>() - rhs->as<ValueType::IntClass>();
|
||||
return IntPool::getInstance().createInt(result);
|
||||
}
|
||||
|
||||
return std::make_shared<Object>(*lhs - *rhs);
|
||||
};
|
||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||
{
|
||||
ValueType::IntClass result = lhs->as<ValueType::IntClass>() - rhs->as<ValueType::IntClass>();
|
||||
return IntPool::getInstance().createInt(result);
|
||||
}
|
||||
return std::make_shared<Object>(*lhs - *rhs);
|
||||
});
|
||||
}
|
||||
case Operator::Multiply: {
|
||||
ObjectPtr lhs = eval(lexp, ctx);
|
||||
ObjectPtr rhs = eval(rexp, ctx);
|
||||
|
||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||
{
|
||||
ValueType::IntClass result = lhs->as<ValueType::IntClass>() * rhs->as<ValueType::IntClass>();
|
||||
return IntPool::getInstance().createInt(result);
|
||||
}
|
||||
|
||||
return std::make_shared<Object>((*lhs) * (*rhs));
|
||||
};
|
||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||
{
|
||||
ValueType::IntClass result = lhs->as<ValueType::IntClass>() * rhs->as<ValueType::IntClass>();
|
||||
return IntPool::getInstance().createInt(result);
|
||||
}
|
||||
return std::make_shared<Object>(*lhs * *rhs);
|
||||
});
|
||||
}
|
||||
case Operator::Divide: {
|
||||
ObjectPtr lhs = eval(lexp, ctx);
|
||||
ObjectPtr rhs = eval(rexp, ctx);
|
||||
return std::make_shared<Object>(*lhs / *rhs);
|
||||
};
|
||||
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);
|
||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||
{
|
||||
ValueType::IntClass lv = lhs->as<ValueType::IntClass>();
|
||||
ValueType::IntClass rv = rhs->as<ValueType::IntClass>();
|
||||
if (rv == 0) { throw ValueError(FString(std::format("Modulo by zero: {} % {}", lv, rv))); }
|
||||
ValueType::IntClass result = lv / rv;
|
||||
ValueType::IntClass r = lv % rv;
|
||||
if (r != 0 && ((lv < 0) != (rv < 0))) { result -= 1; }
|
||||
return IntPool::getInstance().createInt(result);
|
||||
}
|
||||
return std::make_shared<Object>(*lhs % *rhs);
|
||||
});
|
||||
}
|
||||
|
||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||
{
|
||||
ValueType::IntClass lv = lhs->as<ValueType::IntClass>();
|
||||
ValueType::IntClass rv = lhs->as<ValueType::IntClass>();
|
||||
if (rv == 0) { throw ValueError(FString(std::format("Modulo by zero: {} % {}", lv, rv))); }
|
||||
ValueType::IntClass result = lv / rv;
|
||||
ValueType::IntClass r = lv % rv;
|
||||
if (r != 0 && ((lv < 0) != (rv < 0))) { result -= 1; }
|
||||
return IntPool::getInstance().createInt(result);
|
||||
}
|
||||
|
||||
return std::make_shared<Object>(*lhs % *rhs);
|
||||
};
|
||||
case Operator::Power: {
|
||||
ObjectPtr lhs = eval(lexp, ctx);
|
||||
ObjectPtr rhs = eval(rexp, ctx);
|
||||
|
||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||
{
|
||||
ValueType::IntClass result =
|
||||
std::pow(lhs->as<ValueType::IntClass>(), rhs->as<ValueType::IntClass>());
|
||||
return IntPool::getInstance().createInt(result);
|
||||
}
|
||||
return std::make_shared<Object>(power(*lhs, *rhs));
|
||||
}
|
||||
case Operator::And: {
|
||||
ObjectPtr lhs = eval(lexp, ctx);
|
||||
if (lhs->is<bool>() && !isBoolObjectTruthy(lhs))
|
||||
{
|
||||
return Object::getFalseInstance(); // short-circuit
|
||||
}
|
||||
ObjectPtr rhs = eval(rexp, ctx);
|
||||
return std::make_shared<Object>(*lhs && *rhs);
|
||||
};
|
||||
case Operator::Or: {
|
||||
ObjectPtr lhs = eval(lexp, ctx);
|
||||
if (lhs->is<bool>() && isBoolObjectTruthy(lhs))
|
||||
{
|
||||
return Object::getTrueInstance();
|
||||
}
|
||||
ObjectPtr rhs = eval(rexp, ctx);
|
||||
return std::make_shared<Object>(*lhs || *rhs);
|
||||
};
|
||||
case Operator::Equal: {
|
||||
ObjectPtr lhs = eval(lexp, ctx);
|
||||
ObjectPtr rhs = eval(rexp, ctx);
|
||||
return std::make_shared<Object>(*lhs == *rhs);
|
||||
}
|
||||
case Operator::NotEqual: {
|
||||
ObjectPtr lhs = eval(lexp, ctx);
|
||||
ObjectPtr rhs = eval(rexp, ctx);
|
||||
return std::make_shared<Object>(*lhs != *rhs);
|
||||
}
|
||||
case Operator::Less: {
|
||||
ObjectPtr lhs = eval(lexp, ctx);
|
||||
ObjectPtr rhs = eval(rexp, ctx);
|
||||
return std::make_shared<Object>(*lhs < *rhs);
|
||||
}
|
||||
case Operator::LessEqual: {
|
||||
ObjectPtr lhs = eval(lexp, ctx);
|
||||
ObjectPtr rhs = eval(rexp, ctx);
|
||||
return std::make_shared<Object>(*lhs <= *rhs);
|
||||
}
|
||||
case Operator::Greater: {
|
||||
ObjectPtr lhs = eval(lexp, ctx);
|
||||
ObjectPtr rhs = eval(rexp, ctx);
|
||||
return std::make_shared<Object>(*lhs > *rhs);
|
||||
}
|
||||
case Operator::GreaterEqual: {
|
||||
ObjectPtr lhs = eval(lexp, ctx);
|
||||
ObjectPtr rhs = eval(rexp, ctx);
|
||||
return std::make_shared<Object>(*lhs >= *rhs);
|
||||
}
|
||||
case Operator::Is: {
|
||||
ObjectPtr lhs = eval(lexp, ctx);
|
||||
ObjectPtr rhs = eval(rexp, ctx);
|
||||
|
||||
const TypeInfo &lhsType = lhs->getTypeInfo();
|
||||
const TypeInfo &rhsType = rhs->getTypeInfo();
|
||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs, ctx, bin]() {
|
||||
const TypeInfo &lhsType = lhs->getTypeInfo();
|
||||
const TypeInfo &rhsType = rhs->getTypeInfo();
|
||||
|
||||
if (lhs->is<StructInstance>() && rhs->is<StructType>())
|
||||
{
|
||||
const StructInstance &si = lhs->as<StructInstance>();
|
||||
const StructType &st = rhs->as<StructType>();
|
||||
return std::make_shared<Object>(si.parentType == st.type);
|
||||
}
|
||||
if (lhs->is<StructInstance>() && rhs->is<InterfaceType>())
|
||||
{
|
||||
const StructInstance &si = lhs->as<StructInstance>();
|
||||
const InterfaceType &it = rhs->as<InterfaceType>();
|
||||
return std::make_shared<Object>(implements(si.parentType, it.type, ctx));
|
||||
}
|
||||
if (lhs->is<StructInstance>() && rhs->is<StructType>())
|
||||
{
|
||||
const StructInstance &si = lhs->as<StructInstance>();
|
||||
const StructType &st = rhs->as<StructType>();
|
||||
return std::make_shared<Object>(si.parentType == st.type);
|
||||
}
|
||||
if (lhs->is<StructInstance>() && rhs->is<InterfaceType>())
|
||||
{
|
||||
const StructInstance &si = lhs->as<StructInstance>();
|
||||
const InterfaceType &it = rhs->as<InterfaceType>();
|
||||
return std::make_shared<Object>(implements(si.parentType, it.type, ctx));
|
||||
}
|
||||
|
||||
if (ValueType::isTypeBuiltin(lhsType) && rhsType == ValueType::StructType)
|
||||
{
|
||||
const StructType &st = rhs->as<StructType>();
|
||||
const TypeInfo &type = st.type;
|
||||
/*
|
||||
如果是内置类型(e.g. Int, String)
|
||||
那么 eval出来String这个字,出来的是StructType
|
||||
而出来的StructType.type就不会是一个独立的TypeInfo,而是内置的ValueType::String
|
||||
依次我们可以判断内置类型
|
||||
if (ValueType::isTypeBuiltin(lhsType) && rhsType == ValueType::StructType)
|
||||
{
|
||||
const StructType &st = rhs->as<StructType>();
|
||||
const TypeInfo &type = st.type;
|
||||
/*
|
||||
如果是内置类型(e.g. Int, String)
|
||||
那么 eval出来String这个字,出来的是StructType
|
||||
而出来的StructType.type就不会是一个独立的TypeInfo,而是内置的ValueType::String
|
||||
依次我们可以判断内置类型
|
||||
|
||||
e.g:
|
||||
"123" is String
|
||||
L OP R
|
||||
e.g:
|
||||
"123" is String
|
||||
L OP R
|
||||
|
||||
其中 L 类型为 String
|
||||
而 R 类型为 StructType (builtins.hpp) 中注册
|
||||
拿到 R 的 StructType, 其中的 type 为 String
|
||||
*/
|
||||
if (lhs->getTypeInfo() == type) { return Object::getTrueInstance(); }
|
||||
return Object::getFalseInstance();
|
||||
}
|
||||
其中 L 类型为 String
|
||||
而 R 类型为 StructType (builtins.hpp) 中注册
|
||||
拿到 R 的 StructType, 其中的 type 为 String
|
||||
*/
|
||||
if (lhs->getTypeInfo() == type) { return Object::getTrueInstance(); }
|
||||
return Object::getFalseInstance();
|
||||
}
|
||||
|
||||
throw EvaluatorError(u8"TypeError",
|
||||
std::format("Unsupported operator `is` for '{}' && '{}'",
|
||||
prettyType(lhs).toBasicString(),
|
||||
prettyType(rhs).toBasicString()),
|
||||
bin->lexp);
|
||||
throw EvaluatorError(u8"TypeError",
|
||||
std::format("Unsupported operator `is` for '{}' && '{}'",
|
||||
prettyType(lhs).toBasicString(),
|
||||
prettyType(rhs).toBasicString()),
|
||||
bin->lexp);
|
||||
});
|
||||
}
|
||||
|
||||
case Operator::BitAnd: {
|
||||
ObjectPtr lhs = eval(lexp, ctx);
|
||||
ObjectPtr rhs = eval(rexp, ctx);
|
||||
|
||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||
{
|
||||
ValueType::IntClass result = lhs->as<ValueType::IntClass>() & rhs->as<ValueType::IntClass>();
|
||||
return IntPool::getInstance().createInt(result);
|
||||
}
|
||||
return std::make_shared<Object>(bit_and(*lhs, *rhs));
|
||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||
{
|
||||
ValueType::IntClass result = lhs->as<ValueType::IntClass>() & rhs->as<ValueType::IntClass>();
|
||||
return IntPool::getInstance().createInt(result);
|
||||
}
|
||||
return std::make_shared<Object>(bit_and(*lhs, *rhs));
|
||||
});
|
||||
}
|
||||
case Operator::BitOr: {
|
||||
ObjectPtr lhs = eval(lexp, ctx);
|
||||
ObjectPtr rhs = eval(rexp, ctx);
|
||||
|
||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||
{
|
||||
ValueType::IntClass result = lhs->as<ValueType::IntClass>() | rhs->as<ValueType::IntClass>();
|
||||
return IntPool::getInstance().createInt(result);
|
||||
}
|
||||
return std::make_shared<Object>(bit_or(*lhs, *rhs));
|
||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||
{
|
||||
ValueType::IntClass result = lhs->as<ValueType::IntClass>() | rhs->as<ValueType::IntClass>();
|
||||
return IntPool::getInstance().createInt(result);
|
||||
}
|
||||
return std::make_shared<Object>(bit_or(*lhs, *rhs));
|
||||
});
|
||||
}
|
||||
case Operator::BitXor: {
|
||||
ObjectPtr lhs = eval(lexp, ctx);
|
||||
ObjectPtr rhs = eval(rexp, ctx);
|
||||
|
||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||
{
|
||||
ValueType::IntClass result = lhs->as<ValueType::IntClass>() ^ rhs->as<ValueType::IntClass>();
|
||||
return IntPool::getInstance().createInt(result);
|
||||
}
|
||||
return std::make_shared<Object>(bit_xor(*lhs, *rhs));
|
||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||
{
|
||||
ValueType::IntClass result = lhs->as<ValueType::IntClass>() ^ rhs->as<ValueType::IntClass>();
|
||||
return IntPool::getInstance().createInt(result);
|
||||
}
|
||||
return std::make_shared<Object>(bit_xor(*lhs, *rhs));
|
||||
});
|
||||
}
|
||||
case Operator::ShiftLeft: {
|
||||
ObjectPtr lhs = eval(lexp, ctx);
|
||||
ObjectPtr rhs = eval(rexp, ctx);
|
||||
|
||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||
{
|
||||
ValueType::IntClass result = lhs->as<ValueType::IntClass>() << rhs->as<ValueType::IntClass>();
|
||||
return IntPool::getInstance().createInt(result);
|
||||
}
|
||||
return std::make_shared<Object>(shift_left(*lhs, *rhs));
|
||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||
{
|
||||
ValueType::IntClass result = lhs->as<ValueType::IntClass>() << rhs->as<ValueType::IntClass>();
|
||||
return IntPool::getInstance().createInt(result);
|
||||
}
|
||||
return std::make_shared<Object>(shift_left(*lhs, *rhs));
|
||||
});
|
||||
}
|
||||
case Operator::ShiftRight: {
|
||||
ObjectPtr lhs = eval(lexp, ctx);
|
||||
ObjectPtr rhs = eval(rexp, ctx);
|
||||
|
||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||
{
|
||||
ValueType::IntClass result = lhs->as<ValueType::IntClass>() >> rhs->as<ValueType::IntClass>();
|
||||
return IntPool::getInstance().createInt(result);
|
||||
}
|
||||
return std::make_shared<Object>(shift_right(*lhs, *rhs));
|
||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||
{
|
||||
ValueType::IntClass result = lhs->as<ValueType::IntClass>() >> rhs->as<ValueType::IntClass>();
|
||||
return IntPool::getInstance().createInt(result);
|
||||
}
|
||||
return std::make_shared<Object>(shift_right(*lhs, *rhs));
|
||||
});
|
||||
}
|
||||
|
||||
case Operator::Assign: {
|
||||
@@ -242,46 +215,98 @@ namespace Fig
|
||||
lv.set(rhs);
|
||||
return rhs;
|
||||
}
|
||||
|
||||
case Operator::And: {
|
||||
ObjectPtr lhs = eval(lexp, ctx);
|
||||
if (lhs->is<bool>() && !isBoolObjectTruthy(lhs)) { return Object::getFalseInstance(); }
|
||||
ObjectPtr rhs = eval(rexp, ctx);
|
||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs && *rhs); });
|
||||
}
|
||||
case Operator::Or: {
|
||||
ObjectPtr lhs = eval(lexp, ctx);
|
||||
if (lhs->is<bool>() && isBoolObjectTruthy(lhs)) { return Object::getTrueInstance(); }
|
||||
ObjectPtr rhs = 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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs >= *rhs); });
|
||||
}
|
||||
case Operator::PlusAssign: {
|
||||
LvObject lv = evalLv(lexp, ctx);
|
||||
const ObjectPtr &lhs = lv.get();
|
||||
ObjectPtr rhs = eval(rexp, ctx);
|
||||
lv.set(std::make_shared<Object>(*(lv.get()) + *rhs));
|
||||
const ObjectPtr &result =
|
||||
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);
|
||||
const ObjectPtr &lhs = lv.get();
|
||||
ObjectPtr rhs = eval(rexp, ctx);
|
||||
lv.set(std::make_shared<Object>(*(lv.get()) - *rhs));
|
||||
const ObjectPtr &result =
|
||||
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);
|
||||
const ObjectPtr &lhs = lv.get();
|
||||
ObjectPtr rhs = eval(rexp, ctx);
|
||||
lv.set(std::make_shared<Object>(*(lv.get()) * (*rhs)));
|
||||
const ObjectPtr &result =
|
||||
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);
|
||||
const ObjectPtr &lhs = lv.get();
|
||||
ObjectPtr rhs = eval(rexp, ctx);
|
||||
lv.set(std::make_shared<Object>(*(lv.get()) / *rhs));
|
||||
const ObjectPtr &result =
|
||||
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);
|
||||
const ObjectPtr &lhs = lv.get();
|
||||
ObjectPtr rhs = eval(rexp, ctx);
|
||||
lv.set(std::make_shared<Object>(*(lv.get()) / *rhs));
|
||||
const ObjectPtr &result =
|
||||
tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs % *rhs); });
|
||||
lv.set(result);
|
||||
return rhs;
|
||||
}
|
||||
// case Operator::CaretAssign: {
|
||||
// LvObject lv = evalLv(lexp, ctx);
|
||||
// ObjectPtr rhs = eval(rexp, ctx);
|
||||
// lv.set(std::make_shared<Object>(
|
||||
// *(lv.get()) ^ *rhs));
|
||||
// }
|
||||
default:
|
||||
throw EvaluatorError(u8"UnsupportedOp",
|
||||
std::format("Unsupport operator '{}' for binary", magic_enum::enum_name(op)),
|
||||
bin);
|
||||
}
|
||||
}
|
||||
};
|
||||
}; // namespace Fig
|
||||
@@ -1,3 +1,6 @@
|
||||
#include "Ast/functionParameters.hpp"
|
||||
#include "Evaluator/Value/value.hpp"
|
||||
#include <Ast/Expressions/FunctionCall.hpp>
|
||||
#include <Evaluator/Value/function.hpp>
|
||||
#include <Evaluator/Value/LvObject.hpp>
|
||||
#include <Evaluator/evaluator.hpp>
|
||||
@@ -5,41 +8,74 @@
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
RvObject Evaluator::evalFunctionCall(const Function &fn,
|
||||
const Ast::FunctionArguments &fnArgs,
|
||||
const FString &fnName,
|
||||
ContextPtr ctx)
|
||||
RvObject Evaluator::executeFunction(const Function &fn,
|
||||
const Ast::FunctionCallArgs &args,
|
||||
ContextPtr fnCtx) // new context for fn, already filled paras
|
||||
{
|
||||
const Function &fnStruct = fn;
|
||||
// const FString &fnName = fn.name;
|
||||
if (fn.type == Function::Builtin || fn.type == Function::MemberType)
|
||||
{
|
||||
if (fn.type == Function::Builtin) { return fn.builtin(args.argv); }
|
||||
else
|
||||
{
|
||||
return fn.mtFn(nullptr,
|
||||
args.argv); // wrapped member type function (`this` provided by evalMemberExpr)
|
||||
}
|
||||
}
|
||||
// else: normal fn, args is needless
|
||||
for (const auto &stmt : fn.body->stmts)
|
||||
{
|
||||
StatementResult sr = evalStatement(stmt, fnCtx);
|
||||
if (sr.isError())
|
||||
{
|
||||
throw EvaluatorError(u8"UncaughtExceptionError",
|
||||
std::format("Uncaught exception: {}", sr.result->toString().toBasicString()),
|
||||
stmt);
|
||||
}
|
||||
if (!sr.isNormal())
|
||||
{
|
||||
return sr.result;
|
||||
}
|
||||
}
|
||||
return Object::getNullInstance();
|
||||
}
|
||||
RvObject Evaluator::evalFunctionCall(const Ast::FunctionCall &call, ContextPtr ctx)
|
||||
{
|
||||
RvObject fnObj = eval(call->callee, ctx);
|
||||
if (fnObj->getTypeInfo() != ValueType::Function)
|
||||
{
|
||||
throw EvaluatorError(u8"ObjectNotCallable",
|
||||
std::format("Object `{}` isn't callable", fnObj->toString().toBasicString()),
|
||||
call->callee);
|
||||
}
|
||||
|
||||
const Function &fn = fnObj->as<Function>();
|
||||
|
||||
const FString &fnName = fn.name;
|
||||
const Ast::FunctionArguments &fnArgs = call->arg;
|
||||
|
||||
Ast::FunctionCallArgs evaluatedArgs;
|
||||
if (fnStruct.type == Function::Builtin || fnStruct.type == Function::MemberType)
|
||||
if (fn.type == Function::Builtin || fn.type == Function::MemberType)
|
||||
{
|
||||
for (const auto &argExpr : fnArgs.argv) { evaluatedArgs.argv.push_back(eval(argExpr, ctx)); }
|
||||
if (fnStruct.builtinParamCount != -1 && fnStruct.builtinParamCount != evaluatedArgs.getLength())
|
||||
if (fn.builtinParamCount != -1 && fn.builtinParamCount != evaluatedArgs.getLength())
|
||||
{
|
||||
throw EvaluatorError(u8"BuiltinArgumentMismatchError",
|
||||
std::format("Builtin function '{}' expects {} arguments, but {} were provided",
|
||||
fnName.toBasicString(),
|
||||
fnStruct.builtinParamCount,
|
||||
fn.builtinParamCount,
|
||||
evaluatedArgs.getLength()),
|
||||
fnArgs.argv.back());
|
||||
}
|
||||
if (fnStruct.type == Function::Builtin)
|
||||
{
|
||||
return fnStruct.builtin(evaluatedArgs.argv);
|
||||
}
|
||||
else
|
||||
{
|
||||
return fnStruct.mtFn(nullptr, evaluatedArgs.argv); // wrapped member type function (`this` provided by evalMemberExpr)
|
||||
}
|
||||
return executeFunction(fn, evaluatedArgs, nullptr);
|
||||
}
|
||||
|
||||
// check argument, all types of parameters
|
||||
Ast::FunctionParameters fnParas = fnStruct.paras;
|
||||
Ast::FunctionParameters fnParas = fn.paras;
|
||||
|
||||
// create new context for function call
|
||||
auto newContext = std::make_shared<Context>(FString(std::format("<Function {}()>", fnName.toBasicString())),
|
||||
fnStruct.closureContext);
|
||||
fn.closureContext);
|
||||
|
||||
if (fnParas.variadic)
|
||||
goto VariadicFilling;
|
||||
@@ -60,8 +96,8 @@ namespace Fig
|
||||
size_t i;
|
||||
for (i = 0; i < fnParas.posParas.size(); i++)
|
||||
{
|
||||
TypeInfo expectedType(fnParas.posParas[i].second); // look up type info, if exists a type with the
|
||||
// name, use it, else throw
|
||||
const TypeInfo &expectedType = actualType(eval(fnParas.posParas[i].second, ctx)); // look up type info, if exists a type
|
||||
// with the name, use it, else throw
|
||||
ObjectPtr argVal = eval(fnArgs.argv[i], ctx);
|
||||
TypeInfo actualType = argVal->getTypeInfo();
|
||||
if (!isTypeMatch(expectedType, argVal, ctx))
|
||||
@@ -80,7 +116,7 @@ namespace Fig
|
||||
for (; i < fnArgs.getLength(); i++)
|
||||
{
|
||||
size_t defParamIndex = i - fnParas.posParas.size();
|
||||
TypeInfo expectedType(fnParas.defParas[defParamIndex].second.first);
|
||||
const TypeInfo &expectedType = actualType(eval(fnParas.defParas[defParamIndex].second.first, ctx));
|
||||
|
||||
ObjectPtr defaultVal = eval(fnParas.defParas[defParamIndex].second.second, ctx);
|
||||
if (!isTypeMatch(expectedType, defaultVal, ctx))
|
||||
@@ -126,13 +162,13 @@ namespace Fig
|
||||
if (j < fnParas.posParas.size())
|
||||
{
|
||||
paramName = fnParas.posParas[j].first;
|
||||
paramType = TypeInfo(fnParas.posParas[j].second);
|
||||
paramType = actualType(eval(fnParas.posParas[j].second, ctx));
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t defParamIndex = j - fnParas.posParas.size();
|
||||
paramName = fnParas.defParas[defParamIndex].first;
|
||||
paramType = TypeInfo(fnParas.defParas[defParamIndex].second.first);
|
||||
paramType = actualType(eval(fnParas.defParas[defParamIndex].second.first, ctx));
|
||||
}
|
||||
AccessModifier argAm = AccessModifier::Normal;
|
||||
newContext->def(paramName, paramType, argAm, evaluatedArgs.argv[j]);
|
||||
@@ -152,30 +188,16 @@ namespace Fig
|
||||
|
||||
ExecuteBody: {
|
||||
// execute function body
|
||||
ObjectPtr retVal = Object::getNullInstance();
|
||||
for (const auto &stmt : fnStruct.body->stmts)
|
||||
{
|
||||
StatementResult sr = evalStatement(stmt, newContext);
|
||||
if (sr.isError())
|
||||
{
|
||||
throw EvaluatorError(u8"UncaughtExceptionError",
|
||||
std::format("Uncaught exception: {}", sr.result->toString().toBasicString()),
|
||||
stmt);
|
||||
}
|
||||
if (!sr.isNormal())
|
||||
{
|
||||
retVal = sr.result;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isTypeMatch(fnStruct.retType, retVal, ctx))
|
||||
ObjectPtr retVal = executeFunction(fn, evaluatedArgs, newContext);
|
||||
|
||||
if (!isTypeMatch(fn.retType, retVal, ctx))
|
||||
{
|
||||
throw EvaluatorError(u8"ReturnTypeMismatchError",
|
||||
std::format("Function '{}' expects return type '{}', but got type '{}'",
|
||||
fnName.toBasicString(),
|
||||
fnStruct.retType.toString().toBasicString(),
|
||||
fn.retType.toString().toBasicString(),
|
||||
prettyType(retVal).toBasicString()),
|
||||
fnStruct.body);
|
||||
fn.body);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "Evaluator/Value/value.hpp"
|
||||
#include <Evaluator/Value/LvObject.hpp>
|
||||
#include <Evaluator/evaluator.hpp>
|
||||
#include <Evaluator/evaluator_error.hpp>
|
||||
@@ -347,16 +348,13 @@ namespace Fig
|
||||
// load struct method
|
||||
for (auto &[id, fn] : stDefCtx->getFunctions())
|
||||
{
|
||||
auto funcNameOpt = stDefCtx->getFunctionName(id);
|
||||
assert(funcNameOpt.has_value());
|
||||
|
||||
const FString &funcName = *funcNameOpt;
|
||||
auto funcSlot = stDefCtx->get(funcName);
|
||||
|
||||
const FString &funcName = fn.name;
|
||||
const auto &funcSlot = stDefCtx->get(funcName);
|
||||
|
||||
instanceCtx->def(funcName,
|
||||
ValueType::Function,
|
||||
funcSlot->am,
|
||||
std::make_shared<Object>(Function(fn.paras, fn.retType, fn.body, instanceCtx)));
|
||||
std::make_shared<Object>(Function(funcName, fn.paras, fn.retType, fn.body, instanceCtx)));
|
||||
}
|
||||
|
||||
return std::make_shared<Object>(StructInstance(structT.type, instanceCtx));
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "Evaluator/Value/value.hpp"
|
||||
#include <Evaluator/Value/LvObject.hpp>
|
||||
#include <Evaluator/evaluator.hpp>
|
||||
#include <Evaluator/evaluator_error.hpp>
|
||||
@@ -36,6 +37,7 @@ namespace Fig
|
||||
return LvObject(std::make_shared<VariableSlot>(
|
||||
member,
|
||||
std::make_shared<Object>(Function(
|
||||
member,
|
||||
[baseVal, member](ObjectPtr self, std::vector<ObjectPtr> args) -> ObjectPtr {
|
||||
if (self) { return baseVal->getMemberFunction(member)(self, args); }
|
||||
return baseVal->getMemberFunction(member)(baseVal, args);
|
||||
@@ -52,7 +54,8 @@ namespace Fig
|
||||
// e.g. impl xxx for Int
|
||||
|
||||
auto &fn = ctx->getImplementedMethod(baseVal->getTypeInfo(), member);
|
||||
Function boundFn(fn.paras,
|
||||
Function boundFn(member,
|
||||
fn.paras,
|
||||
fn.retType,
|
||||
fn.body,
|
||||
ctx // current context
|
||||
@@ -74,7 +77,8 @@ namespace Fig
|
||||
if (ctx->hasMethodImplemented(si.parentType, member))
|
||||
{
|
||||
auto &fn = ctx->getImplementedMethod(si.parentType, member);
|
||||
Function boundFn(fn.paras,
|
||||
Function boundFn(member,
|
||||
fn.paras,
|
||||
fn.retType,
|
||||
fn.body,
|
||||
si.localContext // create a new function and set closure context
|
||||
@@ -92,7 +96,7 @@ namespace Fig
|
||||
else if (ctx->hasDefaultImplementedMethod(si.parentType, member))
|
||||
{
|
||||
const auto &ifm = ctx->getDefaultImplementedMethod(si.parentType, member);
|
||||
Function fn(ifm.paras, actualType(eval(ifm.returnType, ctx)), ifm.defaultBody, ctx);
|
||||
Function fn(member, ifm.paras, actualType(eval(ifm.returnType, ctx)), ifm.defaultBody, ctx);
|
||||
|
||||
return LvObject(std::make_shared<VariableSlot>(
|
||||
member, std::make_shared<Object>(fn), ValueType::Function, AccessModifier::PublicConst),
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
#include "Ast/AccessModifier.hpp"
|
||||
#include "Ast/Expressions/FunctionCall.hpp"
|
||||
#include "Ast/astBase.hpp"
|
||||
#include "Ast/functionParameters.hpp"
|
||||
#include "Core/fig_string.hpp"
|
||||
#include "Evaluator/Core/StatementResult.hpp"
|
||||
#include "Evaluator/Value/value.hpp"
|
||||
#include <Evaluator/Value/LvObject.hpp>
|
||||
#include <Evaluator/evaluator.hpp>
|
||||
#include <Evaluator/evaluator_error.hpp>
|
||||
|
||||
#include <Utils/utils.hpp>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
@@ -17,7 +25,6 @@ namespace Fig
|
||||
}
|
||||
case VarDefSt: {
|
||||
auto varDef = std::static_pointer_cast<Ast::VarDefAst>(stmt);
|
||||
|
||||
|
||||
if (ctx->containsInThisScope(varDef->name))
|
||||
{
|
||||
@@ -62,7 +69,6 @@ namespace Fig
|
||||
|
||||
case FunctionDefSt: {
|
||||
auto fnDef = std::static_pointer_cast<Ast::FunctionDefSt>(stmt);
|
||||
|
||||
|
||||
const FString &fnName = fnDef->name;
|
||||
if (ctx->containsInThisScope(fnName))
|
||||
@@ -79,7 +85,7 @@ namespace Fig
|
||||
returnType = actualType(returnTypeValue);
|
||||
}
|
||||
|
||||
Function fn(fnDef->paras, returnType, fnDef->body, ctx);
|
||||
Function fn(fnName, fnDef->paras, returnType, fnDef->body, ctx);
|
||||
ctx->def(fnName,
|
||||
ValueType::Function,
|
||||
(fnDef->isPublic ? AccessModifier::PublicConst : AccessModifier::Const),
|
||||
@@ -89,7 +95,6 @@ namespace Fig
|
||||
|
||||
case StructSt: {
|
||||
auto stDef = std::static_pointer_cast<Ast::StructDefSt>(stmt);
|
||||
|
||||
|
||||
if (ctx->containsInThisScope(stDef->name))
|
||||
{
|
||||
@@ -148,7 +153,6 @@ namespace Fig
|
||||
|
||||
case InterfaceDefSt: {
|
||||
auto ifd = std::static_pointer_cast<Ast::InterfaceDefAst>(stmt);
|
||||
|
||||
|
||||
const FString &interfaceName = ifd->name;
|
||||
|
||||
@@ -169,7 +173,6 @@ namespace Fig
|
||||
|
||||
case ImplementSt: {
|
||||
auto ip = std::static_pointer_cast<Ast::ImplementAst>(stmt);
|
||||
|
||||
|
||||
TypeInfo structType(ip->structName);
|
||||
TypeInfo interfaceType(ip->interfaceName);
|
||||
@@ -216,7 +219,148 @@ namespace Fig
|
||||
std::format("Variable `{}` is not a struct type", ip->structName.toBasicString()),
|
||||
ip);
|
||||
}
|
||||
|
||||
auto &implementMethods = ip->methods;
|
||||
|
||||
if (ip->interfaceName == u8"Operation")
|
||||
{
|
||||
// 运算符重载
|
||||
/*
|
||||
impl Operation for xxx
|
||||
{
|
||||
add(l, r) {...}
|
||||
}
|
||||
*/
|
||||
using enum Ast::Operator;
|
||||
static const std::unordered_map<FString, std::pair<Ast::Operator, size_t>> magic_name_to_op = {
|
||||
// 算术
|
||||
{u8"Add", {Ast::Operator::Add, 2}},
|
||||
{u8"Sub", {Ast::Operator::Subtract, 2}},
|
||||
{u8"Mul", {Ast::Operator::Multiply, 2}},
|
||||
{u8"Div", {Ast::Operator::Divide, 2}},
|
||||
{u8"Mod", {Ast::Operator::Modulo, 2}},
|
||||
{u8"Pow", {Ast::Operator::Power, 2}},
|
||||
|
||||
// 逻辑(一元)
|
||||
{u8"Neg", {Ast::Operator::Subtract, 1}}, // 一元负号
|
||||
{u8"Not", {Ast::Operator::Not, 1}},
|
||||
|
||||
// 逻辑(二元)
|
||||
{u8"And", {Ast::Operator::And, 2}},
|
||||
{u8"Or", {Ast::Operator::Or, 2}},
|
||||
|
||||
// 比较
|
||||
{u8"Equal", {Ast::Operator::Equal, 2}},
|
||||
{u8"NotEqual", {Ast::Operator::NotEqual, 2}},
|
||||
{u8"LessThan", {Ast::Operator::Less, 2}},
|
||||
{u8"LessEqual", {Ast::Operator::LessEqual, 2}},
|
||||
{u8"GreaterThan", {Ast::Operator::Greater, 2}},
|
||||
{u8"GreaterEqual", {Ast::Operator::GreaterEqual, 2}},
|
||||
{u8"Is", {Ast::Operator::Is, 2}},
|
||||
|
||||
// 位运算(一元)
|
||||
{u8"BitNot", {Ast::Operator::BitNot, 1}},
|
||||
|
||||
// 位运算(二元)
|
||||
{u8"BitAnd", {Ast::Operator::BitAnd, 2}},
|
||||
{u8"BitOr", {Ast::Operator::BitOr, 2}},
|
||||
{u8"BitXor", {Ast::Operator::BitXor, 2}},
|
||||
{u8"ShiftLeft", {Ast::Operator::ShiftLeft, 2}},
|
||||
{u8"ShiftRight", {Ast::Operator::ShiftRight, 2}},
|
||||
};
|
||||
for (auto &implMethod : implementMethods)
|
||||
{
|
||||
const FString &opName = implMethod.name;
|
||||
if (!magic_name_to_op.contains(opName))
|
||||
{
|
||||
// ... 现在忽略
|
||||
// 未来可能报错
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
auto [op, expectArgCnt] = magic_name_to_op.at(opName);
|
||||
|
||||
// type op isUnary(1-->true, 2-->false)
|
||||
if (ctx->hasOperatorImplemented(structType, op, (expectArgCnt == 1 ? true : false)))
|
||||
{
|
||||
throw EvaluatorError(
|
||||
u8"DuplicateImplementError",
|
||||
std::format("{} has already implement by another interface", opName.toBasicString()),
|
||||
ip);
|
||||
}
|
||||
|
||||
size_t paraCnt = implMethod.paras.posParas.size(); // 必须为位置参数!
|
||||
if (paraCnt != expectArgCnt || implMethod.paras.size() != expectArgCnt)
|
||||
{
|
||||
// 特化报错,更详细易读
|
||||
throw EvaluatorError(u8"InterfaceSignatureMismatch",
|
||||
std::format("Operator {} for {} arg count must be {}, got {}",
|
||||
opName.toBasicString(),
|
||||
structLv.name().toBasicString(),
|
||||
expectArgCnt,
|
||||
paraCnt),
|
||||
ip);
|
||||
}
|
||||
|
||||
FString opFnName(u8"Operation." + prettyType(structTypeObj) + u8"." + opName);
|
||||
|
||||
ContextPtr fnCtx = std::make_shared<Context>(
|
||||
FString(std::format("<Function {}>", opFnName.toBasicString())), ctx);
|
||||
|
||||
const auto &fillOpFnParas = [this, structType, implMethod, opFnName, fnCtx, ctx, paraCnt](
|
||||
const std::vector<ObjectPtr> &args) {
|
||||
const Ast::FunctionParameters ¶s = implMethod.paras;
|
||||
for (size_t i = 0; i < paraCnt; ++i)
|
||||
{
|
||||
const TypeInfo ¶Type = actualType(eval(paras.posParas[i].second, ctx));
|
||||
if (paraType != ValueType::Any && paraType != structType)
|
||||
{
|
||||
throw EvaluatorError(
|
||||
u8"ParameterTypeError",
|
||||
std::format("Invalid op fn parameter type '{}' of `{}`, must be `{}`",
|
||||
paraType.toString().toBasicString(),
|
||||
paras.posParas[i].first.toBasicString(),
|
||||
structType.toString().toBasicString()),
|
||||
paras.posParas[i].second);
|
||||
}
|
||||
fnCtx->def(paras.posParas[i].first, paraType, AccessModifier::Normal, args[i]);
|
||||
}
|
||||
};
|
||||
|
||||
if (paraCnt == 1)
|
||||
{
|
||||
ctx->registerUnaryOperator(structType, op, [=, this](const ObjectPtr &value) -> ObjectPtr {
|
||||
fillOpFnParas({value});
|
||||
return executeFunction(Function(opFnName,
|
||||
implMethod.paras, // parameters
|
||||
structType, // return type --> struct type
|
||||
implMethod.body, // body
|
||||
ctx // closure context
|
||||
),
|
||||
Ast::FunctionCallArgs{.argv = {value}},
|
||||
fnCtx);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->registerBinaryOperator(
|
||||
structType, op, [=, this](const ObjectPtr &lhs, const ObjectPtr &rhs) {
|
||||
fillOpFnParas({lhs, rhs});
|
||||
return executeFunction(Function(opFnName,
|
||||
implMethod.paras, // parameters
|
||||
structType, // return type --> struct type
|
||||
implMethod.body, // body
|
||||
ctx // closure context
|
||||
),
|
||||
Ast::FunctionCallArgs{.argv = {lhs, rhs}},
|
||||
fnCtx);
|
||||
});
|
||||
}
|
||||
}
|
||||
return StatementResult::normal();
|
||||
}
|
||||
|
||||
InterfaceType &interface = interfaceObj->as<InterfaceType>();
|
||||
|
||||
// ===== interface implementation validation =====
|
||||
@@ -291,7 +435,7 @@ namespace Fig
|
||||
ObjectPtr returnTypeValue = eval(ifMethod.returnType, ctx);
|
||||
|
||||
record.implMethods[name] =
|
||||
Function(implMethod.paras, actualType(returnTypeValue), implMethod.body, ctx);
|
||||
Function(implMethod.name, implMethod.paras, actualType(returnTypeValue), implMethod.body, ctx);
|
||||
}
|
||||
|
||||
for (auto &m : interface.methods)
|
||||
@@ -406,7 +550,6 @@ namespace Fig
|
||||
|
||||
case TrySt: {
|
||||
auto tryst = std::static_pointer_cast<Ast::TrySt>(stmt);
|
||||
|
||||
|
||||
ContextPtr tryCtx = std::make_shared<Context>(
|
||||
FString(std::format("<Try at {}:{}>", tryst->getAAI().line, tryst->getAAI().column)), ctx);
|
||||
@@ -445,7 +588,6 @@ namespace Fig
|
||||
|
||||
case ThrowSt: {
|
||||
auto ts = std::static_pointer_cast<Ast::ThrowSt>(stmt);
|
||||
|
||||
|
||||
ObjectPtr value = eval(ts->value, ctx);
|
||||
if (value->is<ValueType::NullClass>())
|
||||
@@ -457,7 +599,6 @@ namespace Fig
|
||||
|
||||
case ReturnSt: {
|
||||
auto returnSt = std::static_pointer_cast<Ast::ReturnSt>(stmt);
|
||||
|
||||
|
||||
ObjectPtr returnValue = Object::getNullInstance(); // default is null
|
||||
if (returnSt->retValue) returnValue = eval(returnSt->retValue, ctx);
|
||||
@@ -495,7 +636,6 @@ namespace Fig
|
||||
|
||||
case BlockStatement: {
|
||||
auto block = std::static_pointer_cast<Ast::BlockStatementAst>(stmt);
|
||||
|
||||
|
||||
ContextPtr blockCtx = std::make_shared<Context>(
|
||||
FString(std::format("<Block at {}:{}>", block->getAAI().line, block->getAAI().column)), ctx);
|
||||
@@ -507,4 +647,4 @@ namespace Fig
|
||||
FString(std::format("Feature stmt {} unsupported yet", magic_enum::enum_name(stmt->getType()))));
|
||||
}
|
||||
}
|
||||
};
|
||||
}; // namespace Fig
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "Evaluator/Value/value.hpp"
|
||||
#include <Evaluator/Value/LvObject.hpp>
|
||||
#include <Evaluator/evaluator.hpp>
|
||||
#include <Evaluator/evaluator_error.hpp>
|
||||
@@ -10,16 +11,31 @@ namespace Fig
|
||||
Operator op = un->op;
|
||||
Ast::Expression exp = un->exp;
|
||||
ObjectPtr value = eval(exp, ctx);
|
||||
|
||||
const auto &tryInvokeOverloadFn = [ctx, op](const ObjectPtr &rhs, const std::function<ObjectPtr()> &rollback) {
|
||||
if (rhs->is<StructInstance>())
|
||||
{
|
||||
// 运算符重载
|
||||
const TypeInfo &type = actualType(rhs);
|
||||
if (ctx->hasOperatorImplemented(type, op))
|
||||
{
|
||||
const auto &fnOpt = ctx->getUnaryOperatorFn(type, op);
|
||||
return (*fnOpt)(rhs);
|
||||
}
|
||||
}
|
||||
return rollback();
|
||||
};
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case Operator::Not: {
|
||||
return std::make_shared<Object>(!(*value));
|
||||
return tryInvokeOverloadFn(value, [value]() { return std::make_shared<Object>(!(*value)); });
|
||||
}
|
||||
case Operator::Subtract: {
|
||||
return std::make_shared<Object>(-(*value));
|
||||
return tryInvokeOverloadFn(value, [value]() { return std::make_shared<Object>(-(*value)); });
|
||||
}
|
||||
case Operator::BitNot: {
|
||||
return std::make_shared<Object>(bit_not((*value)));
|
||||
return tryInvokeOverloadFn(value, [value]() { return std::make_shared<Object>(bit_not(*value)); });
|
||||
}
|
||||
default: {
|
||||
throw EvaluatorError(u8"UnsupportedOpError",
|
||||
@@ -28,4 +44,4 @@ namespace Fig
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}; // namespace Fig
|
||||
Reference in New Issue
Block a user