[Feat] 支持运算符重载!详见文档或 Library/lang/lang.fig中的定义。通过 impl Operation for xxx实现重载
[Impl] 函数参数指定现在也接受一个 exp,逐渐改动其他中...
This commit is contained in:
@@ -17,8 +17,10 @@ namespace Fig::Ast
|
|||||||
func test2(dp1 = 10, dp2:String = "default parameter 2")
|
func test2(dp1 = 10, dp2:String = "default parameter 2")
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using PosParasType = std::vector<std::pair<FString, FString>>;
|
using PosParasType = std::vector<std::pair<FString, Expression>>;
|
||||||
using DefParasType = std::vector<std::pair<FString, std::pair<FString, Expression>>>;
|
// name type exp
|
||||||
|
using DefParasType = std::vector<std::pair<FString, std::pair<Expression, Expression>>>;
|
||||||
|
// name type exp default value
|
||||||
|
|
||||||
PosParasType posParas;
|
PosParasType posParas;
|
||||||
DefParasType defParas; // default parameters
|
DefParasType defParas; // default parameters
|
||||||
@@ -61,9 +63,9 @@ namespace Fig::Ast
|
|||||||
for (auto &p : posParas)
|
for (auto &p : posParas)
|
||||||
{
|
{
|
||||||
out += p.first;
|
out += p.first;
|
||||||
if (!p.second.empty())
|
if (p.second != nullptr)
|
||||||
{
|
{
|
||||||
out += FString(u8":" + p.second);
|
out += FString(u8":" + p.second->toString());
|
||||||
}
|
}
|
||||||
out += u8",";
|
out += u8",";
|
||||||
}
|
}
|
||||||
@@ -75,9 +77,9 @@ namespace Fig::Ast
|
|||||||
for (auto &p : defParas)
|
for (auto &p : defParas)
|
||||||
{
|
{
|
||||||
out += p.first;
|
out += p.first;
|
||||||
if (!p.second.first.empty())
|
if (p.second.first != nullptr)
|
||||||
{
|
{
|
||||||
out += FString(u8":" + p.second.first);
|
out += FString(u8":" + p.second.first->toString());
|
||||||
}
|
}
|
||||||
if (p.second.second != nullptr)
|
if (p.second.second != nullptr)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using std::u8string::u8string;
|
using std::u8string::u8string;
|
||||||
|
using std::u8string::operator=;
|
||||||
|
|
||||||
FString operator+(const FString &x)
|
FString operator+(const FString &x)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Evaluator/Value/function.hpp"
|
|
||||||
#include <Ast/Statements/InterfaceDefSt.hpp>
|
|
||||||
#include <Evaluator/Value/interface.hpp>
|
|
||||||
#include <Evaluator/Value/Type.hpp>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <functional>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include <Ast/astBase.hpp>
|
||||||
|
#include <Ast/Statements/InterfaceDefSt.hpp>
|
||||||
|
#include <Evaluator/Value/function.hpp>
|
||||||
|
#include <Evaluator/Value/interface.hpp>
|
||||||
|
#include <Evaluator/Value/Type.hpp>
|
||||||
#include <Evaluator/Context/context_forward.hpp>
|
#include <Evaluator/Context/context_forward.hpp>
|
||||||
#include <Core/fig_string.hpp>
|
#include <Core/fig_string.hpp>
|
||||||
#include <Evaluator/Value/value.hpp>
|
#include <Evaluator/Value/value.hpp>
|
||||||
@@ -26,6 +28,35 @@ namespace Fig
|
|||||||
std::unordered_map<FString, Function> implMethods;
|
std::unordered_map<FString, Function> implMethods;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct OperationRecord
|
||||||
|
{
|
||||||
|
using UnaryOpFn = std::function<ObjectPtr(const ObjectPtr &)>;
|
||||||
|
using BinaryOpFn = std::function<ObjectPtr(const ObjectPtr &, const ObjectPtr &)>;
|
||||||
|
|
||||||
|
std::unordered_map<Ast::Operator, UnaryOpFn> unOpRec;
|
||||||
|
std::unordered_map<Ast::Operator, BinaryOpFn> binOpRec;
|
||||||
|
|
||||||
|
bool hasUnaryOp(Ast::Operator op) const
|
||||||
|
{
|
||||||
|
return unOpRec.contains(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasBinaryOp(Ast::Operator op) const
|
||||||
|
{
|
||||||
|
return binOpRec.contains(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
const UnaryOpFn &getUnaryOpFn(Ast::Operator op) const
|
||||||
|
{
|
||||||
|
return unOpRec.at(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
const BinaryOpFn &getBinaryOpFn(Ast::Operator op) const
|
||||||
|
{
|
||||||
|
return binOpRec.at(op);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class Context : public std::enable_shared_from_this<Context>
|
class Context : public std::enable_shared_from_this<Context>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@@ -37,7 +68,7 @@ namespace Fig
|
|||||||
|
|
||||||
// implRegistry <Struct, ordered list of ImplRecord>
|
// implRegistry <Struct, ordered list of ImplRecord>
|
||||||
std::unordered_map<TypeInfo, std::vector<ImplRecord>, TypeInfoHash> implRegistry;
|
std::unordered_map<TypeInfo, std::vector<ImplRecord>, TypeInfoHash> implRegistry;
|
||||||
|
std::unordered_map<TypeInfo, OperationRecord, TypeInfoHash> opRegistry;
|
||||||
public:
|
public:
|
||||||
ContextPtr parent;
|
ContextPtr parent;
|
||||||
|
|
||||||
@@ -54,6 +85,7 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
variables.insert(c.variables.begin(), c.variables.end());
|
variables.insert(c.variables.begin(), c.variables.end());
|
||||||
implRegistry.insert(c.implRegistry.begin(), c.implRegistry.end());
|
implRegistry.insert(c.implRegistry.begin(), c.implRegistry.end());
|
||||||
|
opRegistry.insert(c.opRegistry.begin(), c.opRegistry.end());
|
||||||
// structTypeNames.insert(c.structTypeNames.begin(),
|
// structTypeNames.insert(c.structTypeNames.begin(),
|
||||||
// c.structTypeNames.end());
|
// c.structTypeNames.end());
|
||||||
}
|
}
|
||||||
@@ -362,6 +394,72 @@ namespace Fig
|
|||||||
throw ""; // ignore warning
|
throw ""; // ignore warning
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hasOperatorImplemented(const TypeInfo &type, Ast::Operator op, bool isUnary = false) const
|
||||||
|
{
|
||||||
|
auto it = opRegistry.find(type);
|
||||||
|
if (it != opRegistry.end())
|
||||||
|
{
|
||||||
|
const OperationRecord &rec = it->second;
|
||||||
|
if (isUnary)
|
||||||
|
return rec.hasUnaryOp(op);
|
||||||
|
else
|
||||||
|
return rec.hasBinaryOp(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent) return parent->hasOperatorImplemented(type, op, isUnary);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<OperationRecord::UnaryOpFn> getUnaryOperatorFn(const TypeInfo &type, Ast::Operator op) const
|
||||||
|
{
|
||||||
|
auto it = opRegistry.find(type);
|
||||||
|
if (it != opRegistry.end())
|
||||||
|
{
|
||||||
|
const OperationRecord &rec = it->second;
|
||||||
|
if (rec.hasUnaryOp(op)) return rec.getUnaryOpFn(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent) return parent->getUnaryOperatorFn(type, op);
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<OperationRecord::BinaryOpFn> getBinaryOperatorFn(const TypeInfo &type, Ast::Operator op) const
|
||||||
|
{
|
||||||
|
auto it = opRegistry.find(type);
|
||||||
|
if (it != opRegistry.end())
|
||||||
|
{
|
||||||
|
const OperationRecord &rec = it->second;
|
||||||
|
if (rec.hasBinaryOp(op)) return rec.getBinaryOpFn(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent) return parent->getBinaryOperatorFn(type, op);
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerUnaryOperator(const TypeInfo &type, Ast::Operator op, OperationRecord::UnaryOpFn fn)
|
||||||
|
{
|
||||||
|
opRegistry[type].unOpRec[op] = std::move(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerBinaryOperator(const TypeInfo &type, Ast::Operator op, OperationRecord::BinaryOpFn fn)
|
||||||
|
{
|
||||||
|
opRegistry[type].binOpRec[op] = std::move(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool removeUnaryOperator(const TypeInfo &type, Ast::Operator op)
|
||||||
|
{
|
||||||
|
auto it = opRegistry.find(type);
|
||||||
|
if (it != opRegistry.end()) return it->second.unOpRec.erase(op) > 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool removeBinaryOperator(const TypeInfo &type, Ast::Operator op)
|
||||||
|
{
|
||||||
|
auto it = opRegistry.find(type);
|
||||||
|
if (it != opRegistry.end()) return it->second.binOpRec.erase(op) > 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void printStackTrace(std::ostream &os = std::cerr, int indent = 0) const
|
void printStackTrace(std::ostream &os = std::cerr, int indent = 0) const
|
||||||
{
|
{
|
||||||
const Context *ctx = this;
|
const Context *ctx = this;
|
||||||
|
|||||||
@@ -39,27 +39,7 @@ namespace Fig
|
|||||||
|
|
||||||
case AstType::FunctionCall: {
|
case AstType::FunctionCall: {
|
||||||
auto fnCall = std::static_pointer_cast<Ast::FunctionCallExpr>(exp);
|
auto fnCall = std::static_pointer_cast<Ast::FunctionCallExpr>(exp);
|
||||||
|
return evalFunctionCall(fnCall, ctx);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
case AstType::FunctionLiteralExpr: {
|
case AstType::FunctionLiteralExpr: {
|
||||||
auto fnLiteral = std::static_pointer_cast<Ast::FunctionLiteralExprAst>(exp);
|
auto fnLiteral = std::static_pointer_cast<Ast::FunctionLiteralExprAst>(exp);
|
||||||
@@ -84,7 +64,7 @@ namespace Fig
|
|||||||
body = fnLiteral->getBlockBody();
|
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
|
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/value.hpp>
|
||||||
#include <Evaluator/Value/LvObject.hpp>
|
#include <Evaluator/Value/LvObject.hpp>
|
||||||
#include <Evaluator/Value/IntPool.hpp>
|
#include <Evaluator/Value/IntPool.hpp>
|
||||||
#include <Evaluator/evaluator.hpp>
|
#include <Evaluator/evaluator.hpp>
|
||||||
#include <Evaluator/evaluator_error.hpp>
|
#include <Evaluator/evaluator_error.hpp>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
RvObject Evaluator::evalBinary(Ast::BinaryExpr bin, ContextPtr ctx)
|
RvObject Evaluator::evalBinary(Ast::BinaryExpr bin, ContextPtr ctx)
|
||||||
@@ -11,130 +15,88 @@ namespace Fig
|
|||||||
using Ast::Operator;
|
using Ast::Operator;
|
||||||
Operator op = bin->op;
|
Operator op = bin->op;
|
||||||
Ast::Expression lexp = bin->lexp, rexp = bin->rexp;
|
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)
|
switch (op)
|
||||||
{
|
{
|
||||||
case Operator::Add: {
|
case Operator::Add: {
|
||||||
ObjectPtr lhs = eval(lexp, ctx);
|
ObjectPtr lhs = eval(lexp, ctx);
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = eval(rexp, ctx);
|
||||||
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||||
{
|
{
|
||||||
ValueType::IntClass result = lhs->as<ValueType::IntClass>() + rhs->as<ValueType::IntClass>();
|
ValueType::IntClass result = lhs->as<ValueType::IntClass>() + rhs->as<ValueType::IntClass>();
|
||||||
return IntPool::getInstance().createInt(result);
|
return IntPool::getInstance().createInt(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_shared<Object>(*lhs + *rhs);
|
return std::make_shared<Object>(*lhs + *rhs);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
case Operator::Subtract: {
|
case Operator::Subtract: {
|
||||||
ObjectPtr lhs = eval(lexp, ctx);
|
ObjectPtr lhs = eval(lexp, ctx);
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = eval(rexp, ctx);
|
||||||
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||||
{
|
{
|
||||||
ValueType::IntClass result = lhs->as<ValueType::IntClass>() - rhs->as<ValueType::IntClass>();
|
ValueType::IntClass result = lhs->as<ValueType::IntClass>() - rhs->as<ValueType::IntClass>();
|
||||||
return IntPool::getInstance().createInt(result);
|
return IntPool::getInstance().createInt(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_shared<Object>(*lhs - *rhs);
|
return std::make_shared<Object>(*lhs - *rhs);
|
||||||
};
|
});
|
||||||
|
}
|
||||||
case Operator::Multiply: {
|
case Operator::Multiply: {
|
||||||
ObjectPtr lhs = eval(lexp, ctx);
|
ObjectPtr lhs = eval(lexp, ctx);
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = eval(rexp, ctx);
|
||||||
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||||
{
|
{
|
||||||
ValueType::IntClass result = lhs->as<ValueType::IntClass>() * rhs->as<ValueType::IntClass>();
|
ValueType::IntClass result = lhs->as<ValueType::IntClass>() * rhs->as<ValueType::IntClass>();
|
||||||
return IntPool::getInstance().createInt(result);
|
return IntPool::getInstance().createInt(result);
|
||||||
}
|
}
|
||||||
|
return std::make_shared<Object>(*lhs * *rhs);
|
||||||
return std::make_shared<Object>((*lhs) * (*rhs));
|
});
|
||||||
};
|
}
|
||||||
case Operator::Divide: {
|
case Operator::Divide: {
|
||||||
ObjectPtr lhs = eval(lexp, ctx);
|
ObjectPtr lhs = eval(lexp, ctx);
|
||||||
ObjectPtr rhs = eval(rexp, 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: {
|
case Operator::Modulo: {
|
||||||
ObjectPtr lhs = eval(lexp, ctx);
|
ObjectPtr lhs = eval(lexp, ctx);
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = eval(rexp, ctx);
|
||||||
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||||
{
|
{
|
||||||
ValueType::IntClass lv = lhs->as<ValueType::IntClass>();
|
ValueType::IntClass lv = lhs->as<ValueType::IntClass>();
|
||||||
ValueType::IntClass rv = lhs->as<ValueType::IntClass>();
|
ValueType::IntClass rv = rhs->as<ValueType::IntClass>();
|
||||||
if (rv == 0) { throw ValueError(FString(std::format("Modulo by zero: {} % {}", lv, rv))); }
|
if (rv == 0) { throw ValueError(FString(std::format("Modulo by zero: {} % {}", lv, rv))); }
|
||||||
ValueType::IntClass result = lv / rv;
|
ValueType::IntClass result = lv / rv;
|
||||||
ValueType::IntClass r = lv % rv;
|
ValueType::IntClass r = lv % rv;
|
||||||
if (r != 0 && ((lv < 0) != (rv < 0))) { result -= 1; }
|
if (r != 0 && ((lv < 0) != (rv < 0))) { result -= 1; }
|
||||||
return IntPool::getInstance().createInt(result);
|
return IntPool::getInstance().createInt(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_shared<Object>(*lhs % *rhs);
|
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: {
|
case Operator::Is: {
|
||||||
ObjectPtr lhs = eval(lexp, ctx);
|
ObjectPtr lhs = eval(lexp, ctx);
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = eval(rexp, ctx);
|
||||||
|
|
||||||
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs, ctx, bin]() {
|
||||||
const TypeInfo &lhsType = lhs->getTypeInfo();
|
const TypeInfo &lhsType = lhs->getTypeInfo();
|
||||||
const TypeInfo &rhsType = rhs->getTypeInfo();
|
const TypeInfo &rhsType = rhs->getTypeInfo();
|
||||||
|
|
||||||
@@ -178,62 +140,73 @@ namespace Fig
|
|||||||
prettyType(lhs).toBasicString(),
|
prettyType(lhs).toBasicString(),
|
||||||
prettyType(rhs).toBasicString()),
|
prettyType(rhs).toBasicString()),
|
||||||
bin->lexp);
|
bin->lexp);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
case Operator::BitAnd: {
|
case Operator::BitAnd: {
|
||||||
ObjectPtr lhs = eval(lexp, ctx);
|
ObjectPtr lhs = eval(lexp, ctx);
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = eval(rexp, ctx);
|
||||||
|
|
||||||
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||||
{
|
{
|
||||||
ValueType::IntClass result = lhs->as<ValueType::IntClass>() & rhs->as<ValueType::IntClass>();
|
ValueType::IntClass result = lhs->as<ValueType::IntClass>() & rhs->as<ValueType::IntClass>();
|
||||||
return IntPool::getInstance().createInt(result);
|
return IntPool::getInstance().createInt(result);
|
||||||
}
|
}
|
||||||
return std::make_shared<Object>(bit_and(*lhs, *rhs));
|
return std::make_shared<Object>(bit_and(*lhs, *rhs));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
case Operator::BitOr: {
|
case Operator::BitOr: {
|
||||||
ObjectPtr lhs = eval(lexp, ctx);
|
ObjectPtr lhs = eval(lexp, ctx);
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = eval(rexp, ctx);
|
||||||
|
|
||||||
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||||
{
|
{
|
||||||
ValueType::IntClass result = lhs->as<ValueType::IntClass>() | rhs->as<ValueType::IntClass>();
|
ValueType::IntClass result = lhs->as<ValueType::IntClass>() | rhs->as<ValueType::IntClass>();
|
||||||
return IntPool::getInstance().createInt(result);
|
return IntPool::getInstance().createInt(result);
|
||||||
}
|
}
|
||||||
return std::make_shared<Object>(bit_or(*lhs, *rhs));
|
return std::make_shared<Object>(bit_or(*lhs, *rhs));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
case Operator::BitXor: {
|
case Operator::BitXor: {
|
||||||
ObjectPtr lhs = eval(lexp, ctx);
|
ObjectPtr lhs = eval(lexp, ctx);
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = eval(rexp, ctx);
|
||||||
|
|
||||||
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||||
{
|
{
|
||||||
ValueType::IntClass result = lhs->as<ValueType::IntClass>() ^ rhs->as<ValueType::IntClass>();
|
ValueType::IntClass result = lhs->as<ValueType::IntClass>() ^ rhs->as<ValueType::IntClass>();
|
||||||
return IntPool::getInstance().createInt(result);
|
return IntPool::getInstance().createInt(result);
|
||||||
}
|
}
|
||||||
return std::make_shared<Object>(bit_xor(*lhs, *rhs));
|
return std::make_shared<Object>(bit_xor(*lhs, *rhs));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
case Operator::ShiftLeft: {
|
case Operator::ShiftLeft: {
|
||||||
ObjectPtr lhs = eval(lexp, ctx);
|
ObjectPtr lhs = eval(lexp, ctx);
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = eval(rexp, ctx);
|
||||||
|
|
||||||
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||||
{
|
{
|
||||||
ValueType::IntClass result = lhs->as<ValueType::IntClass>() << rhs->as<ValueType::IntClass>();
|
ValueType::IntClass result = lhs->as<ValueType::IntClass>() << rhs->as<ValueType::IntClass>();
|
||||||
return IntPool::getInstance().createInt(result);
|
return IntPool::getInstance().createInt(result);
|
||||||
}
|
}
|
||||||
return std::make_shared<Object>(shift_left(*lhs, *rhs));
|
return std::make_shared<Object>(shift_left(*lhs, *rhs));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
case Operator::ShiftRight: {
|
case Operator::ShiftRight: {
|
||||||
ObjectPtr lhs = eval(lexp, ctx);
|
ObjectPtr lhs = eval(lexp, ctx);
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = eval(rexp, ctx);
|
||||||
|
|
||||||
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||||
{
|
{
|
||||||
ValueType::IntClass result = lhs->as<ValueType::IntClass>() >> rhs->as<ValueType::IntClass>();
|
ValueType::IntClass result = lhs->as<ValueType::IntClass>() >> rhs->as<ValueType::IntClass>();
|
||||||
return IntPool::getInstance().createInt(result);
|
return IntPool::getInstance().createInt(result);
|
||||||
}
|
}
|
||||||
return std::make_shared<Object>(shift_right(*lhs, *rhs));
|
return std::make_shared<Object>(shift_right(*lhs, *rhs));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
case Operator::Assign: {
|
case Operator::Assign: {
|
||||||
@@ -242,46 +215,98 @@ namespace Fig
|
|||||||
lv.set(rhs);
|
lv.set(rhs);
|
||||||
return 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: {
|
case Operator::PlusAssign: {
|
||||||
LvObject lv = evalLv(lexp, ctx);
|
LvObject lv = evalLv(lexp, ctx);
|
||||||
|
const ObjectPtr &lhs = lv.get();
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
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;
|
return rhs;
|
||||||
}
|
}
|
||||||
case Operator::MinusAssign: {
|
case Operator::MinusAssign: {
|
||||||
LvObject lv = evalLv(lexp, ctx);
|
LvObject lv = evalLv(lexp, ctx);
|
||||||
|
const ObjectPtr &lhs = lv.get();
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
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;
|
return rhs;
|
||||||
}
|
}
|
||||||
case Operator::AsteriskAssign: {
|
case Operator::AsteriskAssign: {
|
||||||
LvObject lv = evalLv(lexp, ctx);
|
LvObject lv = evalLv(lexp, ctx);
|
||||||
|
const ObjectPtr &lhs = lv.get();
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
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;
|
return rhs;
|
||||||
}
|
}
|
||||||
case Operator::SlashAssign: {
|
case Operator::SlashAssign: {
|
||||||
LvObject lv = evalLv(lexp, ctx);
|
LvObject lv = evalLv(lexp, ctx);
|
||||||
|
const ObjectPtr &lhs = lv.get();
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
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;
|
return rhs;
|
||||||
}
|
}
|
||||||
case Operator::PercentAssign: {
|
case Operator::PercentAssign: {
|
||||||
LvObject lv = evalLv(lexp, ctx);
|
LvObject lv = evalLv(lexp, ctx);
|
||||||
|
const ObjectPtr &lhs = lv.get();
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
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;
|
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:
|
default:
|
||||||
throw EvaluatorError(u8"UnsupportedOp",
|
throw EvaluatorError(u8"UnsupportedOp",
|
||||||
std::format("Unsupport operator '{}' for binary", magic_enum::enum_name(op)),
|
std::format("Unsupport operator '{}' for binary", magic_enum::enum_name(op)),
|
||||||
bin);
|
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/function.hpp>
|
||||||
#include <Evaluator/Value/LvObject.hpp>
|
#include <Evaluator/Value/LvObject.hpp>
|
||||||
#include <Evaluator/evaluator.hpp>
|
#include <Evaluator/evaluator.hpp>
|
||||||
@@ -5,41 +8,74 @@
|
|||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
RvObject Evaluator::evalFunctionCall(const Function &fn,
|
RvObject Evaluator::executeFunction(const Function &fn,
|
||||||
const Ast::FunctionArguments &fnArgs,
|
const Ast::FunctionCallArgs &args,
|
||||||
const FString &fnName,
|
ContextPtr fnCtx) // new context for fn, already filled paras
|
||||||
ContextPtr ctx)
|
|
||||||
{
|
{
|
||||||
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;
|
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)); }
|
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",
|
throw EvaluatorError(u8"BuiltinArgumentMismatchError",
|
||||||
std::format("Builtin function '{}' expects {} arguments, but {} were provided",
|
std::format("Builtin function '{}' expects {} arguments, but {} were provided",
|
||||||
fnName.toBasicString(),
|
fnName.toBasicString(),
|
||||||
fnStruct.builtinParamCount,
|
fn.builtinParamCount,
|
||||||
evaluatedArgs.getLength()),
|
evaluatedArgs.getLength()),
|
||||||
fnArgs.argv.back());
|
fnArgs.argv.back());
|
||||||
}
|
}
|
||||||
if (fnStruct.type == Function::Builtin)
|
return executeFunction(fn, evaluatedArgs, nullptr);
|
||||||
{
|
|
||||||
return fnStruct.builtin(evaluatedArgs.argv);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return fnStruct.mtFn(nullptr, evaluatedArgs.argv); // wrapped member type function (`this` provided by evalMemberExpr)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check argument, all types of parameters
|
// check argument, all types of parameters
|
||||||
Ast::FunctionParameters fnParas = fnStruct.paras;
|
Ast::FunctionParameters fnParas = fn.paras;
|
||||||
|
|
||||||
// create new context for function call
|
// create new context for function call
|
||||||
auto newContext = std::make_shared<Context>(FString(std::format("<Function {}()>", fnName.toBasicString())),
|
auto newContext = std::make_shared<Context>(FString(std::format("<Function {}()>", fnName.toBasicString())),
|
||||||
fnStruct.closureContext);
|
fn.closureContext);
|
||||||
|
|
||||||
if (fnParas.variadic)
|
if (fnParas.variadic)
|
||||||
goto VariadicFilling;
|
goto VariadicFilling;
|
||||||
@@ -60,8 +96,8 @@ namespace Fig
|
|||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < fnParas.posParas.size(); 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
|
const TypeInfo &expectedType = actualType(eval(fnParas.posParas[i].second, ctx)); // look up type info, if exists a type
|
||||||
// name, use it, else throw
|
// with the name, use it, else throw
|
||||||
ObjectPtr argVal = eval(fnArgs.argv[i], ctx);
|
ObjectPtr argVal = eval(fnArgs.argv[i], ctx);
|
||||||
TypeInfo actualType = argVal->getTypeInfo();
|
TypeInfo actualType = argVal->getTypeInfo();
|
||||||
if (!isTypeMatch(expectedType, argVal, ctx))
|
if (!isTypeMatch(expectedType, argVal, ctx))
|
||||||
@@ -80,7 +116,7 @@ namespace Fig
|
|||||||
for (; i < fnArgs.getLength(); i++)
|
for (; i < fnArgs.getLength(); i++)
|
||||||
{
|
{
|
||||||
size_t defParamIndex = i - fnParas.posParas.size();
|
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);
|
ObjectPtr defaultVal = eval(fnParas.defParas[defParamIndex].second.second, ctx);
|
||||||
if (!isTypeMatch(expectedType, defaultVal, ctx))
|
if (!isTypeMatch(expectedType, defaultVal, ctx))
|
||||||
@@ -126,13 +162,13 @@ namespace Fig
|
|||||||
if (j < fnParas.posParas.size())
|
if (j < fnParas.posParas.size())
|
||||||
{
|
{
|
||||||
paramName = fnParas.posParas[j].first;
|
paramName = fnParas.posParas[j].first;
|
||||||
paramType = TypeInfo(fnParas.posParas[j].second);
|
paramType = actualType(eval(fnParas.posParas[j].second, ctx));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
size_t defParamIndex = j - fnParas.posParas.size();
|
size_t defParamIndex = j - fnParas.posParas.size();
|
||||||
paramName = fnParas.defParas[defParamIndex].first;
|
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;
|
AccessModifier argAm = AccessModifier::Normal;
|
||||||
newContext->def(paramName, paramType, argAm, evaluatedArgs.argv[j]);
|
newContext->def(paramName, paramType, argAm, evaluatedArgs.argv[j]);
|
||||||
@@ -152,30 +188,16 @@ namespace Fig
|
|||||||
|
|
||||||
ExecuteBody: {
|
ExecuteBody: {
|
||||||
// execute function body
|
// execute function body
|
||||||
ObjectPtr retVal = Object::getNullInstance();
|
ObjectPtr retVal = executeFunction(fn, evaluatedArgs, newContext);
|
||||||
for (const auto &stmt : fnStruct.body->stmts)
|
|
||||||
{
|
if (!isTypeMatch(fn.retType, retVal, ctx))
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
throw EvaluatorError(u8"ReturnTypeMismatchError",
|
throw EvaluatorError(u8"ReturnTypeMismatchError",
|
||||||
std::format("Function '{}' expects return type '{}', but got type '{}'",
|
std::format("Function '{}' expects return type '{}', but got type '{}'",
|
||||||
fnName.toBasicString(),
|
fnName.toBasicString(),
|
||||||
fnStruct.retType.toString().toBasicString(),
|
fn.retType.toString().toBasicString(),
|
||||||
prettyType(retVal).toBasicString()),
|
prettyType(retVal).toBasicString()),
|
||||||
fnStruct.body);
|
fn.body);
|
||||||
}
|
}
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include "Evaluator/Value/value.hpp"
|
||||||
#include <Evaluator/Value/LvObject.hpp>
|
#include <Evaluator/Value/LvObject.hpp>
|
||||||
#include <Evaluator/evaluator.hpp>
|
#include <Evaluator/evaluator.hpp>
|
||||||
#include <Evaluator/evaluator_error.hpp>
|
#include <Evaluator/evaluator_error.hpp>
|
||||||
@@ -347,16 +348,13 @@ namespace Fig
|
|||||||
// load struct method
|
// load struct method
|
||||||
for (auto &[id, fn] : stDefCtx->getFunctions())
|
for (auto &[id, fn] : stDefCtx->getFunctions())
|
||||||
{
|
{
|
||||||
auto funcNameOpt = stDefCtx->getFunctionName(id);
|
const FString &funcName = fn.name;
|
||||||
assert(funcNameOpt.has_value());
|
const auto &funcSlot = stDefCtx->get(funcName);
|
||||||
|
|
||||||
const FString &funcName = *funcNameOpt;
|
|
||||||
auto funcSlot = stDefCtx->get(funcName);
|
|
||||||
|
|
||||||
instanceCtx->def(funcName,
|
instanceCtx->def(funcName,
|
||||||
ValueType::Function,
|
ValueType::Function,
|
||||||
funcSlot->am,
|
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));
|
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/Value/LvObject.hpp>
|
||||||
#include <Evaluator/evaluator.hpp>
|
#include <Evaluator/evaluator.hpp>
|
||||||
#include <Evaluator/evaluator_error.hpp>
|
#include <Evaluator/evaluator_error.hpp>
|
||||||
@@ -36,6 +37,7 @@ namespace Fig
|
|||||||
return LvObject(std::make_shared<VariableSlot>(
|
return LvObject(std::make_shared<VariableSlot>(
|
||||||
member,
|
member,
|
||||||
std::make_shared<Object>(Function(
|
std::make_shared<Object>(Function(
|
||||||
|
member,
|
||||||
[baseVal, member](ObjectPtr self, std::vector<ObjectPtr> args) -> ObjectPtr {
|
[baseVal, member](ObjectPtr self, std::vector<ObjectPtr> args) -> ObjectPtr {
|
||||||
if (self) { return baseVal->getMemberFunction(member)(self, args); }
|
if (self) { return baseVal->getMemberFunction(member)(self, args); }
|
||||||
return baseVal->getMemberFunction(member)(baseVal, args);
|
return baseVal->getMemberFunction(member)(baseVal, args);
|
||||||
@@ -52,7 +54,8 @@ namespace Fig
|
|||||||
// e.g. impl xxx for Int
|
// e.g. impl xxx for Int
|
||||||
|
|
||||||
auto &fn = ctx->getImplementedMethod(baseVal->getTypeInfo(), member);
|
auto &fn = ctx->getImplementedMethod(baseVal->getTypeInfo(), member);
|
||||||
Function boundFn(fn.paras,
|
Function boundFn(member,
|
||||||
|
fn.paras,
|
||||||
fn.retType,
|
fn.retType,
|
||||||
fn.body,
|
fn.body,
|
||||||
ctx // current context
|
ctx // current context
|
||||||
@@ -74,7 +77,8 @@ namespace Fig
|
|||||||
if (ctx->hasMethodImplemented(si.parentType, member))
|
if (ctx->hasMethodImplemented(si.parentType, member))
|
||||||
{
|
{
|
||||||
auto &fn = ctx->getImplementedMethod(si.parentType, member);
|
auto &fn = ctx->getImplementedMethod(si.parentType, member);
|
||||||
Function boundFn(fn.paras,
|
Function boundFn(member,
|
||||||
|
fn.paras,
|
||||||
fn.retType,
|
fn.retType,
|
||||||
fn.body,
|
fn.body,
|
||||||
si.localContext // create a new function and set closure context
|
si.localContext // create a new function and set closure context
|
||||||
@@ -92,7 +96,7 @@ namespace Fig
|
|||||||
else if (ctx->hasDefaultImplementedMethod(si.parentType, member))
|
else if (ctx->hasDefaultImplementedMethod(si.parentType, member))
|
||||||
{
|
{
|
||||||
const auto &ifm = ctx->getDefaultImplementedMethod(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>(
|
return LvObject(std::make_shared<VariableSlot>(
|
||||||
member, std::make_shared<Object>(fn), ValueType::Function, AccessModifier::PublicConst),
|
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/Value/LvObject.hpp>
|
||||||
#include <Evaluator/evaluator.hpp>
|
#include <Evaluator/evaluator.hpp>
|
||||||
#include <Evaluator/evaluator_error.hpp>
|
#include <Evaluator/evaluator_error.hpp>
|
||||||
|
|
||||||
#include <Utils/utils.hpp>
|
#include <Utils/utils.hpp>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
@@ -18,7 +26,6 @@ namespace Fig
|
|||||||
case VarDefSt: {
|
case VarDefSt: {
|
||||||
auto varDef = std::static_pointer_cast<Ast::VarDefAst>(stmt);
|
auto varDef = std::static_pointer_cast<Ast::VarDefAst>(stmt);
|
||||||
|
|
||||||
|
|
||||||
if (ctx->containsInThisScope(varDef->name))
|
if (ctx->containsInThisScope(varDef->name))
|
||||||
{
|
{
|
||||||
throw EvaluatorError(
|
throw EvaluatorError(
|
||||||
@@ -63,7 +70,6 @@ namespace Fig
|
|||||||
case FunctionDefSt: {
|
case FunctionDefSt: {
|
||||||
auto fnDef = std::static_pointer_cast<Ast::FunctionDefSt>(stmt);
|
auto fnDef = std::static_pointer_cast<Ast::FunctionDefSt>(stmt);
|
||||||
|
|
||||||
|
|
||||||
const FString &fnName = fnDef->name;
|
const FString &fnName = fnDef->name;
|
||||||
if (ctx->containsInThisScope(fnName))
|
if (ctx->containsInThisScope(fnName))
|
||||||
{
|
{
|
||||||
@@ -79,7 +85,7 @@ namespace Fig
|
|||||||
returnType = actualType(returnTypeValue);
|
returnType = actualType(returnTypeValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
Function fn(fnDef->paras, returnType, fnDef->body, ctx);
|
Function fn(fnName, fnDef->paras, returnType, fnDef->body, ctx);
|
||||||
ctx->def(fnName,
|
ctx->def(fnName,
|
||||||
ValueType::Function,
|
ValueType::Function,
|
||||||
(fnDef->isPublic ? AccessModifier::PublicConst : AccessModifier::Const),
|
(fnDef->isPublic ? AccessModifier::PublicConst : AccessModifier::Const),
|
||||||
@@ -90,7 +96,6 @@ namespace Fig
|
|||||||
case StructSt: {
|
case StructSt: {
|
||||||
auto stDef = std::static_pointer_cast<Ast::StructDefSt>(stmt);
|
auto stDef = std::static_pointer_cast<Ast::StructDefSt>(stmt);
|
||||||
|
|
||||||
|
|
||||||
if (ctx->containsInThisScope(stDef->name))
|
if (ctx->containsInThisScope(stDef->name))
|
||||||
{
|
{
|
||||||
throw EvaluatorError(
|
throw EvaluatorError(
|
||||||
@@ -149,7 +154,6 @@ namespace Fig
|
|||||||
case InterfaceDefSt: {
|
case InterfaceDefSt: {
|
||||||
auto ifd = std::static_pointer_cast<Ast::InterfaceDefAst>(stmt);
|
auto ifd = std::static_pointer_cast<Ast::InterfaceDefAst>(stmt);
|
||||||
|
|
||||||
|
|
||||||
const FString &interfaceName = ifd->name;
|
const FString &interfaceName = ifd->name;
|
||||||
|
|
||||||
if (ctx->containsInThisScope(interfaceName))
|
if (ctx->containsInThisScope(interfaceName))
|
||||||
@@ -170,7 +174,6 @@ namespace Fig
|
|||||||
case ImplementSt: {
|
case ImplementSt: {
|
||||||
auto ip = std::static_pointer_cast<Ast::ImplementAst>(stmt);
|
auto ip = std::static_pointer_cast<Ast::ImplementAst>(stmt);
|
||||||
|
|
||||||
|
|
||||||
TypeInfo structType(ip->structName);
|
TypeInfo structType(ip->structName);
|
||||||
TypeInfo interfaceType(ip->interfaceName);
|
TypeInfo interfaceType(ip->interfaceName);
|
||||||
if (ctx->hasImplRegisted(structType, interfaceType))
|
if (ctx->hasImplRegisted(structType, interfaceType))
|
||||||
@@ -216,7 +219,148 @@ namespace Fig
|
|||||||
std::format("Variable `{}` is not a struct type", ip->structName.toBasicString()),
|
std::format("Variable `{}` is not a struct type", ip->structName.toBasicString()),
|
||||||
ip);
|
ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &implementMethods = ip->methods;
|
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>();
|
InterfaceType &interface = interfaceObj->as<InterfaceType>();
|
||||||
|
|
||||||
// ===== interface implementation validation =====
|
// ===== interface implementation validation =====
|
||||||
@@ -291,7 +435,7 @@ namespace Fig
|
|||||||
ObjectPtr returnTypeValue = eval(ifMethod.returnType, ctx);
|
ObjectPtr returnTypeValue = eval(ifMethod.returnType, ctx);
|
||||||
|
|
||||||
record.implMethods[name] =
|
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)
|
for (auto &m : interface.methods)
|
||||||
@@ -407,7 +551,6 @@ namespace Fig
|
|||||||
case TrySt: {
|
case TrySt: {
|
||||||
auto tryst = std::static_pointer_cast<Ast::TrySt>(stmt);
|
auto tryst = std::static_pointer_cast<Ast::TrySt>(stmt);
|
||||||
|
|
||||||
|
|
||||||
ContextPtr tryCtx = std::make_shared<Context>(
|
ContextPtr tryCtx = std::make_shared<Context>(
|
||||||
FString(std::format("<Try at {}:{}>", tryst->getAAI().line, tryst->getAAI().column)), ctx);
|
FString(std::format("<Try at {}:{}>", tryst->getAAI().line, tryst->getAAI().column)), ctx);
|
||||||
StatementResult sr = StatementResult::normal();
|
StatementResult sr = StatementResult::normal();
|
||||||
@@ -446,7 +589,6 @@ namespace Fig
|
|||||||
case ThrowSt: {
|
case ThrowSt: {
|
||||||
auto ts = std::static_pointer_cast<Ast::ThrowSt>(stmt);
|
auto ts = std::static_pointer_cast<Ast::ThrowSt>(stmt);
|
||||||
|
|
||||||
|
|
||||||
ObjectPtr value = eval(ts->value, ctx);
|
ObjectPtr value = eval(ts->value, ctx);
|
||||||
if (value->is<ValueType::NullClass>())
|
if (value->is<ValueType::NullClass>())
|
||||||
{
|
{
|
||||||
@@ -458,7 +600,6 @@ namespace Fig
|
|||||||
case ReturnSt: {
|
case ReturnSt: {
|
||||||
auto returnSt = std::static_pointer_cast<Ast::ReturnSt>(stmt);
|
auto returnSt = std::static_pointer_cast<Ast::ReturnSt>(stmt);
|
||||||
|
|
||||||
|
|
||||||
ObjectPtr returnValue = Object::getNullInstance(); // default is null
|
ObjectPtr returnValue = Object::getNullInstance(); // default is null
|
||||||
if (returnSt->retValue) returnValue = eval(returnSt->retValue, ctx);
|
if (returnSt->retValue) returnValue = eval(returnSt->retValue, ctx);
|
||||||
return StatementResult::returnFlow(returnValue);
|
return StatementResult::returnFlow(returnValue);
|
||||||
@@ -496,7 +637,6 @@ namespace Fig
|
|||||||
case BlockStatement: {
|
case BlockStatement: {
|
||||||
auto block = std::static_pointer_cast<Ast::BlockStatementAst>(stmt);
|
auto block = std::static_pointer_cast<Ast::BlockStatementAst>(stmt);
|
||||||
|
|
||||||
|
|
||||||
ContextPtr blockCtx = std::make_shared<Context>(
|
ContextPtr blockCtx = std::make_shared<Context>(
|
||||||
FString(std::format("<Block at {}:{}>", block->getAAI().line, block->getAAI().column)), ctx);
|
FString(std::format("<Block at {}:{}>", block->getAAI().line, block->getAAI().column)), ctx);
|
||||||
return evalBlockStatement(block, blockCtx);
|
return evalBlockStatement(block, blockCtx);
|
||||||
@@ -507,4 +647,4 @@ namespace Fig
|
|||||||
FString(std::format("Feature stmt {} unsupported yet", magic_enum::enum_name(stmt->getType()))));
|
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/Value/LvObject.hpp>
|
||||||
#include <Evaluator/evaluator.hpp>
|
#include <Evaluator/evaluator.hpp>
|
||||||
#include <Evaluator/evaluator_error.hpp>
|
#include <Evaluator/evaluator_error.hpp>
|
||||||
@@ -10,16 +11,31 @@ namespace Fig
|
|||||||
Operator op = un->op;
|
Operator op = un->op;
|
||||||
Ast::Expression exp = un->exp;
|
Ast::Expression exp = un->exp;
|
||||||
ObjectPtr value = eval(exp, ctx);
|
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)
|
switch (op)
|
||||||
{
|
{
|
||||||
case Operator::Not: {
|
case Operator::Not: {
|
||||||
return std::make_shared<Object>(!(*value));
|
return tryInvokeOverloadFn(value, [value]() { return std::make_shared<Object>(!(*value)); });
|
||||||
}
|
}
|
||||||
case Operator::Subtract: {
|
case Operator::Subtract: {
|
||||||
return std::make_shared<Object>(-(*value));
|
return tryInvokeOverloadFn(value, [value]() { return std::make_shared<Object>(-(*value)); });
|
||||||
}
|
}
|
||||||
case Operator::BitNot: {
|
case Operator::BitNot: {
|
||||||
return std::make_shared<Object>(bit_not((*value)));
|
return tryInvokeOverloadFn(value, [value]() { return std::make_shared<Object>(bit_not(*value)); });
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
throw EvaluatorError(u8"UnsupportedOpError",
|
throw EvaluatorError(u8"UnsupportedOpError",
|
||||||
@@ -28,4 +44,4 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}; // namespace Fig
|
||||||
@@ -16,6 +16,7 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::size_t id;
|
std::size_t id;
|
||||||
|
FString name;
|
||||||
|
|
||||||
enum FnType
|
enum FnType
|
||||||
{
|
{
|
||||||
@@ -52,11 +53,13 @@ namespace Fig
|
|||||||
new (&body) Ast::BlockStatement();
|
new (&body) Ast::BlockStatement();
|
||||||
}
|
}
|
||||||
|
|
||||||
Function(Ast::FunctionParameters _paras,
|
Function(const FString &_name,
|
||||||
|
Ast::FunctionParameters _paras,
|
||||||
TypeInfo _retType,
|
TypeInfo _retType,
|
||||||
Ast::BlockStatement _body,
|
Ast::BlockStatement _body,
|
||||||
ContextPtr _closureContext) :
|
ContextPtr _closureContext) :
|
||||||
id(nextId()), // 分配唯一 ID
|
id(nextId()), // 分配唯一 ID
|
||||||
|
name(_name),
|
||||||
paras(std::move(_paras)),
|
paras(std::move(_paras)),
|
||||||
retType(std::move(_retType)),
|
retType(std::move(_retType)),
|
||||||
body(std::move(_body)),
|
body(std::move(_body)),
|
||||||
@@ -65,25 +68,22 @@ namespace Fig
|
|||||||
type = Normal;
|
type = Normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
Function(std::function<std::shared_ptr<Object>(const std::vector<std::shared_ptr<Object>> &)> fn, int argc) :
|
Function(const FString &_name, std::function<std::shared_ptr<Object>(const std::vector<std::shared_ptr<Object>> &)> fn, int argc) :
|
||||||
id(nextId()), type(Builtin), builtin(fn), builtinParamCount(argc)
|
id(nextId()), name(_name), type(Builtin), builtin(fn), builtinParamCount(argc)
|
||||||
{
|
{
|
||||||
type = Builtin;
|
type = Builtin;
|
||||||
}
|
}
|
||||||
|
|
||||||
Function(std::function<std::shared_ptr<Object>(std::shared_ptr<Object>,
|
Function(const FString &_name, std::function<std::shared_ptr<Object>(std::shared_ptr<Object>,
|
||||||
const std::vector<std::shared_ptr<Object>> &)> fn,
|
const std::vector<std::shared_ptr<Object>> &)> fn,
|
||||||
int argc) :
|
int argc) :
|
||||||
id(nextId()), type(MemberType), mtFn(fn), builtinParamCount(argc)
|
id(nextId()), name(_name), type(MemberType), mtFn(fn), builtinParamCount(argc)
|
||||||
{
|
{
|
||||||
type = MemberType;
|
type = MemberType;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== Copy / Move =====
|
// ===== Copy / Move =====
|
||||||
Function(const Function &other)
|
Function(const Function &other) { copyFrom(other); }
|
||||||
{
|
|
||||||
copyFrom(other);
|
|
||||||
}
|
|
||||||
Function &operator=(const Function &other)
|
Function &operator=(const Function &other)
|
||||||
{
|
{
|
||||||
if (this != &other)
|
if (this != &other)
|
||||||
@@ -94,10 +94,7 @@ namespace Fig
|
|||||||
return *this;
|
return *this;
|
||||||
};
|
};
|
||||||
|
|
||||||
~Function()
|
~Function() { destroy(); }
|
||||||
{
|
|
||||||
destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== Comparison =====
|
// ===== Comparison =====
|
||||||
bool operator==(const Function &other) const noexcept { return id == other.id; }
|
bool operator==(const Function &other) const noexcept { return id == other.id; }
|
||||||
@@ -125,6 +122,7 @@ namespace Fig
|
|||||||
|
|
||||||
void copyFrom(const Function &other)
|
void copyFrom(const Function &other)
|
||||||
{
|
{
|
||||||
|
name = other.name;
|
||||||
type = other.type;
|
type = other.type;
|
||||||
id = nextId(); // 每个复制都生成新的ID
|
id = nextId(); // 每个复制都生成新的ID
|
||||||
builtinParamCount = other.builtinParamCount;
|
builtinParamCount = other.builtinParamCount;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include <Evaluator/Value/interface.hpp>
|
||||||
#include <Evaluator/Value/structType.hpp>
|
#include <Evaluator/Value/structType.hpp>
|
||||||
#include <Evaluator/Value/value_forward.hpp>
|
#include <Evaluator/Value/value_forward.hpp>
|
||||||
#include <Evaluator/Value/Type.hpp>
|
#include <Evaluator/Value/Type.hpp>
|
||||||
@@ -84,6 +85,11 @@ namespace Fig
|
|||||||
return obj->as<StructType>().type;
|
return obj->as<StructType>().type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (t == ValueType::InterfaceType)
|
||||||
|
{
|
||||||
|
return obj->as<InterfaceType>().type;
|
||||||
|
}
|
||||||
|
|
||||||
if (t == ValueType::StructInstance) return obj->as<StructInstance>().parentType;
|
if (t == ValueType::StructInstance) return obj->as<StructInstance>().parentType;
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <unordered_set>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -87,9 +88,8 @@ namespace Fig
|
|||||||
Module,
|
Module,
|
||||||
InterfaceType>;
|
InterfaceType>;
|
||||||
|
|
||||||
|
static std::unordered_map<TypeInfo, std::unordered_map<FString, BuiltinTypeMemberFn>, TypeInfoHash>
|
||||||
|
getMemberTypeFunctions()
|
||||||
static std::unordered_map<TypeInfo, std::unordered_map<FString, BuiltinTypeMemberFn>, TypeInfoHash> getMemberTypeFunctions()
|
|
||||||
{
|
{
|
||||||
static const std::unordered_map<TypeInfo, std::unordered_map<FString, BuiltinTypeMemberFn>, TypeInfoHash>
|
static const std::unordered_map<TypeInfo, std::unordered_map<FString, BuiltinTypeMemberFn>, TypeInfoHash>
|
||||||
memberTypeFunctions{
|
memberTypeFunctions{
|
||||||
@@ -241,9 +241,8 @@ namespace Fig
|
|||||||
return memberTypeFunctions;
|
return memberTypeFunctions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::unordered_map<TypeInfo, std::unordered_map<FString, int>, TypeInfoHash>
|
||||||
|
getMemberTypeFunctionsParas()
|
||||||
static std::unordered_map<TypeInfo, std::unordered_map<FString, int>, TypeInfoHash> getMemberTypeFunctionsParas()
|
|
||||||
{
|
{
|
||||||
static const std::unordered_map<TypeInfo, std::unordered_map<FString, int>, TypeInfoHash>
|
static const std::unordered_map<TypeInfo, std::unordered_map<FString, int>, TypeInfoHash>
|
||||||
memberTypeFunctionsParas{
|
memberTypeFunctionsParas{
|
||||||
@@ -425,7 +424,7 @@ namespace Fig
|
|||||||
return toString();
|
return toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
FString toString() const
|
FString toString(std::unordered_set<const Object *> &visited) const
|
||||||
{
|
{
|
||||||
if (is<ValueType::NullClass>()) return FString(u8"null");
|
if (is<ValueType::NullClass>()) return FString(u8"null");
|
||||||
if (is<ValueType::IntClass>()) return FString(std::to_string(as<ValueType::IntClass>()));
|
if (is<ValueType::IntClass>()) return FString(std::to_string(as<ValueType::IntClass>()));
|
||||||
@@ -445,13 +444,16 @@ namespace Fig
|
|||||||
static_cast<const void *>(&as<StructInstance>())));
|
static_cast<const void *>(&as<StructInstance>())));
|
||||||
if (is<List>())
|
if (is<List>())
|
||||||
{
|
{
|
||||||
|
if (visited.contains(this)) { return u8"[...]"; }
|
||||||
|
visited.insert(this);
|
||||||
|
|
||||||
FString output(u8"[");
|
FString output(u8"[");
|
||||||
const List &list = as<List>();
|
const List &list = as<List>();
|
||||||
bool first_flag = true;
|
bool first_flag = true;
|
||||||
for (auto &ele : list)
|
for (auto &ele : list)
|
||||||
{
|
{
|
||||||
if (!first_flag) output += u8", ";
|
if (!first_flag) output += u8", ";
|
||||||
output += ele.value->toString();
|
output += ele.value->toString(visited);
|
||||||
first_flag = false;
|
first_flag = false;
|
||||||
}
|
}
|
||||||
output += u8"]";
|
output += u8"]";
|
||||||
@@ -459,13 +461,16 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
if (is<Map>())
|
if (is<Map>())
|
||||||
{
|
{
|
||||||
|
if (visited.contains(this)) { return u8"{...}"; }
|
||||||
|
visited.insert(this);
|
||||||
|
|
||||||
FString output(u8"{");
|
FString output(u8"{");
|
||||||
const Map &map = as<Map>();
|
const Map &map = as<Map>();
|
||||||
bool first_flag = true;
|
bool first_flag = true;
|
||||||
for (auto &[key, value] : map)
|
for (auto &[key, value] : map)
|
||||||
{
|
{
|
||||||
if (!first_flag) output += u8", ";
|
if (!first_flag) output += u8", ";
|
||||||
output += key.value->toString() + FString(u8" : ") + value->toString();
|
output += key.value->toString(visited) + FString(u8" : ") + value->toString(visited);
|
||||||
first_flag = false;
|
first_flag = false;
|
||||||
}
|
}
|
||||||
output += u8"}";
|
output += u8"}";
|
||||||
@@ -486,6 +491,12 @@ namespace Fig
|
|||||||
return FString(u8"<error>");
|
return FString(u8"<error>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FString toString() const
|
||||||
|
{
|
||||||
|
std::unordered_set<const Object *> visited{};
|
||||||
|
return toString(visited);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::string
|
static std::string
|
||||||
makeTypeErrorMessage(const char *prefix, const char *op, const Object &lhs, const Object &rhs)
|
makeTypeErrorMessage(const char *prefix, const char *op, const Object &lhs, const Object &rhs)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include <Ast/Expressions/FunctionCall.hpp>
|
||||||
#include <Ast/Expressions/InitExpr.hpp>
|
#include <Ast/Expressions/InitExpr.hpp>
|
||||||
#include <Ast/Statements/ImplementSt.hpp>
|
#include <Ast/Statements/ImplementSt.hpp>
|
||||||
#include <Ast/Statements/InterfaceDefSt.hpp>
|
#include <Ast/Statements/InterfaceDefSt.hpp>
|
||||||
@@ -24,15 +25,9 @@ namespace Fig
|
|||||||
FString sourcePath;
|
FString sourcePath;
|
||||||
std::vector<FString> sourceLines;
|
std::vector<FString> sourceLines;
|
||||||
|
|
||||||
void SetSourcePath(const FString &sp)
|
void SetSourcePath(const FString &sp) { sourcePath = sp; }
|
||||||
{
|
|
||||||
sourcePath = sp;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetSourceLines(const std::vector<FString> &sl)
|
void SetSourceLines(const std::vector<FString> &sl) { sourceLines = sl; }
|
||||||
{
|
|
||||||
sourceLines = sl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetGlobalContext(ContextPtr ctx)
|
void SetGlobalContext(ContextPtr ctx)
|
||||||
{
|
{
|
||||||
@@ -40,11 +35,7 @@ namespace Fig
|
|||||||
global = ctx;
|
global = ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateGlobalContext()
|
void CreateGlobalContext() { global = std::make_shared<Context>(FString(u8"<Global>")); }
|
||||||
{
|
|
||||||
global = std::make_shared<Context>(
|
|
||||||
FString(u8"<Global>"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegisterBuiltins() // only function
|
void RegisterBuiltins() // only function
|
||||||
{
|
{
|
||||||
@@ -53,12 +44,8 @@ namespace Fig
|
|||||||
for (auto &[name, fn] : Builtins::getBuiltinFunctions())
|
for (auto &[name, fn] : Builtins::getBuiltinFunctions())
|
||||||
{
|
{
|
||||||
int argc = Builtins::getBuiltinFunctionParamCount(name);
|
int argc = Builtins::getBuiltinFunctionParamCount(name);
|
||||||
Function f(fn, argc);
|
Function f(name, fn, argc);
|
||||||
global->def(
|
global->def(name, ValueType::Function, AccessModifier::Const, std::make_shared<Object>(f));
|
||||||
name,
|
|
||||||
ValueType::Function,
|
|
||||||
AccessModifier::Const,
|
|
||||||
std::make_shared<Object>(f));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,11 +55,7 @@ namespace Fig
|
|||||||
|
|
||||||
for (auto &[name, val] : Builtins::getBuiltinValues())
|
for (auto &[name, val] : Builtins::getBuiltinValues())
|
||||||
{
|
{
|
||||||
global->def(
|
global->def(name, val->getTypeInfo(), AccessModifier::Const, val);
|
||||||
name,
|
|
||||||
val->getTypeInfo(),
|
|
||||||
AccessModifier::Const,
|
|
||||||
val);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,7 +74,11 @@ namespace Fig
|
|||||||
RvObject evalUnary(Ast::UnaryExpr, ContextPtr); // unary expr
|
RvObject evalUnary(Ast::UnaryExpr, ContextPtr); // unary expr
|
||||||
RvObject evalTernary(Ast::TernaryExpr, ContextPtr); // ternary expr
|
RvObject evalTernary(Ast::TernaryExpr, ContextPtr); // ternary expr
|
||||||
|
|
||||||
RvObject evalFunctionCall(const Function &, const Ast::FunctionArguments &, const FString &, ContextPtr); // function call
|
RvObject executeFunction(const Function &fn, const Ast::FunctionCallArgs &, ContextPtr); // fn, fn context
|
||||||
|
|
||||||
|
RvObject evalFunctionCall(const Ast::FunctionCall &,
|
||||||
|
ContextPtr); // function call
|
||||||
|
|
||||||
RvObject eval(Ast::Expression, ContextPtr);
|
RvObject eval(Ast::Expression, ContextPtr);
|
||||||
|
|
||||||
StatementResult evalBlockStatement(Ast::BlockStatement, ContextPtr); // block
|
StatementResult evalBlockStatement(Ast::BlockStatement, ContextPtr); // block
|
||||||
|
|||||||
@@ -16,16 +16,21 @@ namespace Fig
|
|||||||
std::source_location loc = std::source_location::current())
|
std::source_location loc = std::source_location::current())
|
||||||
{
|
{
|
||||||
message = msg;
|
message = msg;
|
||||||
line = ast->getAAI().line;
|
|
||||||
column = ast->getAAI().column;
|
|
||||||
|
|
||||||
src_loc = std::move(loc);
|
src_loc = std::move(loc);
|
||||||
|
|
||||||
typeName = std::move(_typeName);
|
typeName = std::move(_typeName);
|
||||||
|
|
||||||
|
if (ast != nullptr)
|
||||||
|
{
|
||||||
|
line = ast->getAAI().line;
|
||||||
|
column = ast->getAAI().column;
|
||||||
sourcePath = *ast->getAAI().sourcePath;
|
sourcePath = *ast->getAAI().sourcePath;
|
||||||
sourceLines = *ast->getAAI().sourceLines;
|
sourceLines = *ast->getAAI().sourceLines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
EvaluatorError(FString _typeName,
|
EvaluatorError(FString _typeName,
|
||||||
std::string_view msg,
|
std::string_view msg,
|
||||||
Ast::AstBase ast,
|
Ast::AstBase ast,
|
||||||
|
|||||||
@@ -31,6 +31,44 @@ public interface Error
|
|||||||
getErrorMessage() -> String;
|
getErrorMessage() -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Operation interface
|
||||||
|
|
||||||
|
public interface Operation
|
||||||
|
{
|
||||||
|
// math
|
||||||
|
Add(T, T) -> T;
|
||||||
|
Sub(T, T) -> T;
|
||||||
|
Mul(T, T) -> T;
|
||||||
|
Div(T, T) -> T;
|
||||||
|
Mod(T, T) -> T;
|
||||||
|
Pow(T, T) -> T;
|
||||||
|
|
||||||
|
// logic
|
||||||
|
Neg(T) -> T;
|
||||||
|
Not(T) -> T;
|
||||||
|
|
||||||
|
And(T, T) -> T;
|
||||||
|
Or(T, T) -> T;
|
||||||
|
|
||||||
|
// comparision
|
||||||
|
Equal(T, T) -> T;
|
||||||
|
NotEqual(T, T) -> T;
|
||||||
|
LessThan(T, T) -> T;
|
||||||
|
LessEqual(T, T) -> T;
|
||||||
|
GreaterThan(T, T) -> T;
|
||||||
|
GreaterEqual(T, T) -> T;
|
||||||
|
Is(T, T) -> T;
|
||||||
|
|
||||||
|
// Bit
|
||||||
|
BitNot(T) -> T;
|
||||||
|
|
||||||
|
BitAnd(T, T) -> T;
|
||||||
|
BitOr(T, T) -> T;
|
||||||
|
BitXor(T, T) -> T;
|
||||||
|
ShiftLeft(T, T) -> T;
|
||||||
|
ShiftRight(T, T) -> T:
|
||||||
|
}
|
||||||
|
|
||||||
public struct Any {}
|
public struct Any {}
|
||||||
public struct Int {}
|
public struct Int {}
|
||||||
public struct Null {}
|
public struct Null {}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ namespace Fig::Builtins
|
|||||||
Ast::FunctionParameters({}, {}),
|
Ast::FunctionParameters({}, {}),
|
||||||
std::make_shared<Ast::VarExprAst>(u8"String"),
|
std::make_shared<Ast::VarExprAst>(u8"String"),
|
||||||
nullptr)}))},
|
nullptr)}))},
|
||||||
|
{u8"Operation", std::make_shared<Object>(InterfaceType(getOperationInterfaceTypeInfo(), {}))},
|
||||||
|
|
||||||
{u8"Any", std::make_shared<Object>(StructType(ValueType::Any, nullptr, {}, true))},
|
{u8"Any", std::make_shared<Object>(StructType(ValueType::Any, nullptr, {}, true))},
|
||||||
{u8"Int", std::make_shared<Object>(StructType(ValueType::Int, nullptr, {}, true))},
|
{u8"Int", std::make_shared<Object>(StructType(ValueType::Int, nullptr, {}, true))},
|
||||||
|
|||||||
@@ -7,22 +7,15 @@
|
|||||||
#include <Evaluator/Value/value.hpp>
|
#include <Evaluator/Value/value.hpp>
|
||||||
#include <Core/runtimeTime.hpp>
|
#include <Core/runtimeTime.hpp>
|
||||||
|
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
namespace Builtins
|
namespace Builtins
|
||||||
{
|
{
|
||||||
|
|
||||||
inline static const TypeInfo &getErrorInterfaceTypeInfo()
|
|
||||||
{
|
|
||||||
static const TypeInfo ErrorInterfaceTypeInfo(u8"Error", true);
|
|
||||||
return ErrorInterfaceTypeInfo;
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
// error's interface like:
|
// error's interface like:
|
||||||
interface Error
|
interface Error
|
||||||
@@ -33,15 +26,33 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
inline static const TypeInfo &getErrorInterfaceTypeInfo()
|
||||||
|
{
|
||||||
|
static const TypeInfo ErrorInterfaceTypeInfo(u8"Error", true);
|
||||||
|
return ErrorInterfaceTypeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
interface Operation
|
||||||
|
{
|
||||||
|
add(..., ...) -> ...;
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
inline static const TypeInfo &getOperationInterfaceTypeInfo()
|
||||||
|
{
|
||||||
|
static const TypeInfo OperationInterfaceTypeInfo(u8"Operation", true);
|
||||||
|
return OperationInterfaceTypeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
const std::unordered_map<FString, ObjectPtr> &getBuiltinValues();
|
const std::unordered_map<FString, ObjectPtr> &getBuiltinValues();
|
||||||
|
|
||||||
using BuiltinFunction = std::function<ObjectPtr(const std::vector<ObjectPtr> &)>;
|
using BuiltinFunction = std::function<ObjectPtr(const std::vector<ObjectPtr> &)>;
|
||||||
|
|
||||||
|
|
||||||
const std::unordered_map<FString, int> &getBuiltinFunctionArgCounts();
|
const std::unordered_map<FString, int> &getBuiltinFunctionArgCounts();
|
||||||
const std::unordered_map<FString, BuiltinFunction> &getBuiltinFunctions();
|
const std::unordered_map<FString, BuiltinFunction> &getBuiltinFunctions();
|
||||||
|
|
||||||
|
|
||||||
inline bool isBuiltinFunction(const FString &name)
|
inline bool isBuiltinFunction(const FString &name)
|
||||||
{
|
{
|
||||||
return getBuiltinFunctions().find(name) != getBuiltinFunctions().end();
|
return getBuiltinFunctions().find(name) != getBuiltinFunctions().end();
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include "Ast/Expressions/VarExpr.hpp"
|
||||||
#include <Ast/Statements/ErrorFlow.hpp>
|
#include <Ast/Statements/ErrorFlow.hpp>
|
||||||
#include <Ast/Statements/ImplementSt.hpp>
|
#include <Ast/Statements/ImplementSt.hpp>
|
||||||
#include <Ast/astBase.hpp>
|
#include <Ast/astBase.hpp>
|
||||||
@@ -184,7 +185,7 @@ namespace Fig
|
|||||||
if (isThis(TokenType::Assign)) // =
|
if (isThis(TokenType::Assign)) // =
|
||||||
{
|
{
|
||||||
next();
|
next();
|
||||||
dp.push_back({pname, {ValueType::Any.name, parseExpression(0, TokenType::Comma)}});
|
dp.push_back({pname, {makeAst<Ast::VarExprAst>(u8"Any"), parseExpression(0, TokenType::Comma)}});
|
||||||
if (isThis(TokenType::Comma))
|
if (isThis(TokenType::Comma))
|
||||||
{
|
{
|
||||||
next(); // only skip `,` when it's there
|
next(); // only skip `,` when it's there
|
||||||
@@ -193,13 +194,11 @@ namespace Fig
|
|||||||
else if (isThis(TokenType::Colon)) // :
|
else if (isThis(TokenType::Colon)) // :
|
||||||
{
|
{
|
||||||
next(); // skip `:`
|
next(); // skip `:`
|
||||||
expect(TokenType::Identifier, FString(u8"Type name"));
|
Ast::Expression type_exp = parseExpression(0, TokenType::Comma, TokenType::RightParen, TokenType::Assign);
|
||||||
FString ti(currentToken().getValue());
|
|
||||||
next(); // skip type name
|
|
||||||
if (isThis(TokenType::Assign)) // =
|
if (isThis(TokenType::Assign)) // =
|
||||||
{
|
{
|
||||||
next(); // skip `=`
|
next(); // skip `=`
|
||||||
dp.push_back({pname, {ti, parseExpression(0, TokenType::Comma)}});
|
dp.push_back({pname, {type_exp, parseExpression(0, TokenType::Comma)}});
|
||||||
if (isThis(TokenType::Comma))
|
if (isThis(TokenType::Comma))
|
||||||
{
|
{
|
||||||
next(); // only skip `,` when it's there
|
next(); // only skip `,` when it's there
|
||||||
@@ -207,7 +206,7 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pp.push_back({pname, ti});
|
pp.push_back({pname, type_exp});
|
||||||
if (isThis(TokenType::Comma))
|
if (isThis(TokenType::Comma))
|
||||||
{
|
{
|
||||||
next(); // only skip `,` when it's there
|
next(); // only skip `,` when it's there
|
||||||
@@ -228,7 +227,7 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pp.push_back({pname, ValueType::Any.name});
|
pp.push_back({pname, makeAst<Ast::VarExprAst>(u8"Any")});
|
||||||
if (isThis(TokenType::Comma))
|
if (isThis(TokenType::Comma))
|
||||||
{
|
{
|
||||||
next(); // only skip `,` when it's there
|
next(); // only skip `,` when it's there
|
||||||
@@ -1020,14 +1019,14 @@ namespace Fig
|
|||||||
return makeAst<Ast::ImportSt>(path);
|
return makeAst<Ast::ImportSt>(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ast::Expression Parser::parseExpression(Precedence bp, TokenType stop, TokenType stop2)
|
Ast::Expression Parser::parseExpression(Precedence bp, TokenType stop, TokenType stop2, TokenType stop3)
|
||||||
{
|
{
|
||||||
Ast::Expression lhs;
|
Ast::Expression lhs;
|
||||||
Ast::Operator op;
|
Ast::Operator op;
|
||||||
|
|
||||||
Token tok = currentToken();
|
Token tok = currentToken();
|
||||||
if (tok == EOFTok) throwAddressableError<SyntaxError>(FString(u8"Unexpected end of expression"));
|
if (tok == EOFTok) throwAddressableError<SyntaxError>(FString(u8"Unexpected end of expression"));
|
||||||
if (tok.getType() == stop || tok.getType() == stop2)
|
if (tok.getType() == stop || tok.getType() == stop2 || tok.getType() == stop3)
|
||||||
{
|
{
|
||||||
if (lhs == nullptr) throwAddressableError<SyntaxError>(FString(u8"Expected expression"));
|
if (lhs == nullptr) throwAddressableError<SyntaxError>(FString(u8"Expected expression"));
|
||||||
return lhs;
|
return lhs;
|
||||||
@@ -1089,7 +1088,7 @@ namespace Fig
|
|||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
tok = currentToken();
|
tok = currentToken();
|
||||||
if (tok.getType() == stop || tok.getType() == stop2 || tok == EOFTok) break;
|
if (tok.getType() == stop || tok.getType() == stop2 || tok.getType() == stop3 || tok == EOFTok) break;
|
||||||
|
|
||||||
/* Postfix */
|
/* Postfix */
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Token/token.hpp"
|
||||||
#include <Ast/astBase.hpp>
|
#include <Ast/astBase.hpp>
|
||||||
#include <Ast/ast.hpp>
|
#include <Ast/ast.hpp>
|
||||||
#include <Lexer/lexer.hpp>
|
#include <Lexer/lexer.hpp>
|
||||||
@@ -322,7 +323,7 @@ namespace Fig
|
|||||||
Ast::Import __parseImport(); // entry: current is Token::Import
|
Ast::Import __parseImport(); // entry: current is Token::Import
|
||||||
|
|
||||||
Ast::Statement __parseStatement(bool = true); // entry: (idk)
|
Ast::Statement __parseStatement(bool = true); // entry: (idk)
|
||||||
Ast::Expression parseExpression(Precedence, TokenType = TokenType::Semicolon, TokenType = TokenType::Semicolon);
|
Ast::Expression parseExpression(Precedence, TokenType = TokenType::Semicolon, TokenType = TokenType::Semicolon, TokenType = TokenType::Semicolon);
|
||||||
std::vector<Ast::AstBase> parseAll();
|
std::vector<Ast::AstBase> parseAll();
|
||||||
};
|
};
|
||||||
}; // namespace Fig
|
}; // namespace Fig
|
||||||
Reference in New Issue
Block a user