forked from PuqiAR/Fig-TreeWalker
挺大的改动。增加 as运算符,转换不了抛出 TypeError。import语法更新。修复try一点错误。现在表达式运算返回ExprResult。通过3个宏实现简便错误传播与解包 unwrap
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
"name": "fig-vscode",
|
"name": "fig-vscode",
|
||||||
"displayName": "Fig Language",
|
"displayName": "Fig Language",
|
||||||
"description": "VSCode extension for Fig language with syntax highlighting",
|
"description": "VSCode extension for Fig language with syntax highlighting",
|
||||||
"version": "0.4.2",
|
"version": "0.4.3",
|
||||||
"publisher": "PuqiAR",
|
"publisher": "PuqiAR",
|
||||||
"engines": {
|
"engines": {
|
||||||
"vscode": "^1.90.0"
|
"vscode": "^1.90.0"
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
"patterns": [
|
"patterns": [
|
||||||
{
|
{
|
||||||
"name": "keyword.control.fig",
|
"name": "keyword.control.fig",
|
||||||
"match": "\\b(and|or|not|import|func|var|const|final|while|for|if|else|new|struct|interface|impl|public|return|break|continue|try|catch|throw)\\b"
|
"match": "\\b(and|or|not|import|func|var|const|final|while|for|if|else|new|struct|interface|impl|public|return|break|continue|try|catch|throw|is|as)\\b"
|
||||||
},
|
},
|
||||||
{ "name": "constant.language.fig", "match": "\\b(true|false|null)\\b" }
|
{ "name": "constant.language.fig", "match": "\\b(true|false|null)\\b" }
|
||||||
]
|
]
|
||||||
@@ -78,7 +78,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "keyword.operator.comparison.fig",
|
"name": "keyword.operator.comparison.fig",
|
||||||
"match": "(==|!=|<=|>=|<|>|is)"
|
"match": "(==|!=|<=|>=|<|>)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "punctuation.separator.fig",
|
"name": "punctuation.separator.fig",
|
||||||
|
|||||||
@@ -6,18 +6,26 @@
|
|||||||
|
|
||||||
namespace Fig::Ast
|
namespace Fig::Ast
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
import std.io as stdio; // io --> stdio;
|
||||||
|
import std.io {print, println};
|
||||||
|
*/
|
||||||
|
|
||||||
class ImportSt final : public StatementAst
|
class ImportSt final : public StatementAst
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::vector<FString> path;
|
std::vector<FString> path;
|
||||||
|
std::vector<FString> names;
|
||||||
|
|
||||||
|
FString rename;
|
||||||
|
|
||||||
ImportSt()
|
ImportSt()
|
||||||
{
|
{
|
||||||
type = AstType::ImportSt;
|
type = AstType::ImportSt;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImportSt(std::vector<FString> _path) :
|
ImportSt(std::vector<FString> _path, std::vector<FString> _names, const FString &_rename) :
|
||||||
path(std::move(_path))
|
path(std::move(_path)), names(std::move(_names)), rename(_rename)
|
||||||
{
|
{
|
||||||
type = AstType::ImportSt;
|
type = AstType::ImportSt;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -199,6 +199,9 @@ namespace Fig::Ast
|
|||||||
GreaterEqual, // >=
|
GreaterEqual, // >=
|
||||||
Is, // a is b
|
Is, // a is b
|
||||||
|
|
||||||
|
// 转换
|
||||||
|
As, // 3.14 as Int
|
||||||
|
|
||||||
// 三目
|
// 三目
|
||||||
TernaryCond,
|
TernaryCond,
|
||||||
|
|
||||||
@@ -235,6 +238,8 @@ namespace Fig::Ast
|
|||||||
Operator::Equal, Operator::NotEqual, Operator::Less, Operator::LessEqual,
|
Operator::Equal, Operator::NotEqual, Operator::Less, Operator::LessEqual,
|
||||||
Operator::Greater, Operator::GreaterEqual, Operator::Is,
|
Operator::Greater, Operator::GreaterEqual, Operator::Is,
|
||||||
|
|
||||||
|
Operator::As,
|
||||||
|
|
||||||
Operator::BitAnd, Operator::BitOr, Operator::BitXor, Operator::BitNot,
|
Operator::BitAnd, Operator::BitOr, Operator::BitXor, Operator::BitNot,
|
||||||
Operator::ShiftLeft, Operator::ShiftRight,
|
Operator::ShiftLeft, Operator::ShiftRight,
|
||||||
|
|
||||||
@@ -271,6 +276,9 @@ namespace Fig::Ast
|
|||||||
{TokenType::GreaterEqual, Operator::GreaterEqual},
|
{TokenType::GreaterEqual, Operator::GreaterEqual},
|
||||||
{TokenType::Is, Operator::Is},
|
{TokenType::Is, Operator::Is},
|
||||||
|
|
||||||
|
// 转换
|
||||||
|
{TokenType::As, Operator::As},
|
||||||
|
|
||||||
// 三目
|
// 三目
|
||||||
{TokenType::Question, Operator::TernaryCond},
|
{TokenType::Question, Operator::TernaryCond},
|
||||||
|
|
||||||
|
|||||||
@@ -97,6 +97,14 @@ namespace Fig
|
|||||||
std::print("{}{}{}", colorCode, msg, TerminalColors::Reset);
|
std::print("{}{}{}", colorCode, msg, TerminalColors::Reset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void logFigErrorInterface(const FString &errorClass, const FString &errorMessage)
|
||||||
|
{
|
||||||
|
namespace TC = TerminalColors;
|
||||||
|
coloredPrint(TC::LightWhite, "Uncaught Fig exception:\n");
|
||||||
|
coloredPrint(TC::LightRed, "✖ ");
|
||||||
|
coloredPrint(TC::Red, errorClass.toBasicString() + ": ");
|
||||||
|
coloredPrint(TC::Red, errorMessage.toBasicString() + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
inline void logAddressableError(const AddressableError &err)
|
inline void logAddressableError(const AddressableError &err)
|
||||||
{
|
{
|
||||||
@@ -117,7 +125,6 @@ namespace Fig
|
|||||||
if (fileName != u8"<stdin>")
|
if (fileName != u8"<stdin>")
|
||||||
{
|
{
|
||||||
lineContent = ((int64_t(err.getLine()) - int64_t(1)) >= 0 ? sourceLines[err.getLine() - 1] : u8"<No Source>");
|
lineContent = ((int64_t(err.getLine()) - int64_t(1)) >= 0 ? sourceLines[err.getLine() - 1] : u8"<No Source>");
|
||||||
FString pointerLine;
|
|
||||||
for (size_t i = 1; i < err.getColumn(); ++i)
|
for (size_t i = 1; i < err.getColumn(); ++i)
|
||||||
{
|
{
|
||||||
if (lineContent[i - 1] == U'\t') { pointerLine += U'\t'; }
|
if (lineContent[i - 1] == U'\t') { pointerLine += U'\t'; }
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include <Core/fig_string.hpp>
|
#include <Core/fig_string.hpp>
|
||||||
#include <Evaluator/Value/value.hpp>
|
#include <Evaluator/Value/value.hpp>
|
||||||
#include <Evaluator/Value/VariableSlot.hpp>
|
#include <Evaluator/Value/VariableSlot.hpp>
|
||||||
|
#include <Evaluator/Core/ExprResult.hpp>
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
@@ -30,8 +31,8 @@ namespace Fig
|
|||||||
|
|
||||||
struct OperationRecord
|
struct OperationRecord
|
||||||
{
|
{
|
||||||
using UnaryOpFn = std::function<ObjectPtr(const ObjectPtr &)>;
|
using UnaryOpFn = std::function<ExprResult(const ObjectPtr &)>;
|
||||||
using BinaryOpFn = std::function<ObjectPtr(const ObjectPtr &, const ObjectPtr &)>;
|
using BinaryOpFn = std::function<ExprResult(const ObjectPtr &, const ObjectPtr &)>;
|
||||||
|
|
||||||
std::unordered_map<Ast::Operator, UnaryOpFn> unOpRec;
|
std::unordered_map<Ast::Operator, UnaryOpFn> unOpRec;
|
||||||
std::unordered_map<Ast::Operator, BinaryOpFn> binOpRec;
|
std::unordered_map<Ast::Operator, BinaryOpFn> binOpRec;
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
#include <Evaluator/evaluator.hpp>
|
#include <Evaluator/evaluator.hpp>
|
||||||
#include <Evaluator/evaluator_error.hpp>
|
#include <Evaluator/evaluator_error.hpp>
|
||||||
|
#include <Evaluator/Core/ExprResult.hpp>
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
RvObject Evaluator::eval(Ast::Expression exp, ContextPtr ctx)
|
ExprResult Evaluator::eval(Ast::Expression exp, ContextPtr ctx)
|
||||||
{
|
{
|
||||||
using Ast::AstType;
|
using Ast::AstType;
|
||||||
AstType type = exp->getType();
|
AstType type = exp->getType();
|
||||||
@@ -17,7 +18,7 @@ namespace Fig
|
|||||||
case AstType::VarExpr: {
|
case AstType::VarExpr: {
|
||||||
auto varExpr = std::static_pointer_cast<Ast::VarExprAst>(exp);
|
auto varExpr = std::static_pointer_cast<Ast::VarExprAst>(exp);
|
||||||
|
|
||||||
return evalVarExpr(varExpr, ctx).get(); // LvObject -> RvObject
|
return check_unwrap_lv(evalVarExpr(varExpr, ctx)).get(); // LvObject -> RvObject
|
||||||
}
|
}
|
||||||
case AstType::BinaryExpr: {
|
case AstType::BinaryExpr: {
|
||||||
auto bin = std::static_pointer_cast<Ast::BinaryExprAst>(exp);
|
auto bin = std::static_pointer_cast<Ast::BinaryExprAst>(exp);
|
||||||
@@ -35,7 +36,7 @@ namespace Fig
|
|||||||
return evalTernary(te, ctx);
|
return evalTernary(te, ctx);
|
||||||
}
|
}
|
||||||
case AstType::MemberExpr:
|
case AstType::MemberExpr:
|
||||||
case AstType::IndexExpr: return evalLv(exp, ctx).get();
|
case AstType::IndexExpr: return check_unwrap_lv(evalLv(exp, ctx)).get();
|
||||||
|
|
||||||
case AstType::FunctionCall: {
|
case AstType::FunctionCall: {
|
||||||
auto fnCall = std::static_pointer_cast<Ast::FunctionCallExpr>(exp);
|
auto fnCall = std::static_pointer_cast<Ast::FunctionCallExpr>(exp);
|
||||||
@@ -82,7 +83,7 @@ namespace Fig
|
|||||||
|
|
||||||
|
|
||||||
List list;
|
List list;
|
||||||
for (auto &exp : lstExpr->val) { list.push_back(eval(exp, ctx)); }
|
for (auto &exp : lstExpr->val) { list.push_back(check_unwrap(eval(exp, ctx))); }
|
||||||
return std::make_shared<Object>(std::move(list));
|
return std::make_shared<Object>(std::move(list));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,7 +92,9 @@ namespace Fig
|
|||||||
|
|
||||||
|
|
||||||
Map map;
|
Map map;
|
||||||
for (auto &[key, value] : mapExpr->val) { map[eval(key, ctx)] = eval(value, ctx); }
|
for (auto &[key, value] : mapExpr->val) {
|
||||||
|
map[check_unwrap(eval(key, ctx))] = check_unwrap(eval(value, ctx));
|
||||||
|
}
|
||||||
return std::make_shared<Object>(std::move(map));
|
return std::make_shared<Object>(std::move(map));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +1,27 @@
|
|||||||
#include <Ast/Expressions/BinaryExpr.hpp>
|
#include <Ast/Expressions/BinaryExpr.hpp>
|
||||||
#include <Evaluator/Value/value.hpp>
|
#include <Evaluator/Value/value.hpp>
|
||||||
|
#include <Evaluator/Value/Type.hpp>
|
||||||
|
#include <Evaluator/Value/Type.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 <Evaluator/Core/ExprResult.hpp>
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
RvObject Evaluator::evalBinary(Ast::BinaryExpr bin, ContextPtr ctx)
|
ExprResult Evaluator::evalBinary(Ast::BinaryExpr bin, ContextPtr ctx)
|
||||||
{
|
{
|
||||||
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 =
|
const auto &tryInvokeOverloadFn =
|
||||||
[ctx, op](const ObjectPtr &lhs, const ObjectPtr &rhs, const std::function<ObjectPtr()> &rollback) {
|
[ctx, op](const ObjectPtr &lhs, const ObjectPtr &rhs, const std::function<ExprResult()> &rollback) {
|
||||||
if (lhs->is<StructInstance>() && lhs->getTypeInfo() == rhs->getTypeInfo())
|
if (lhs->is<StructInstance>() && lhs->getTypeInfo() == rhs->getTypeInfo())
|
||||||
{
|
{
|
||||||
// 运算符重载
|
// 运算符重载
|
||||||
@@ -34,8 +38,8 @@ namespace Fig
|
|||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
case Operator::Add: {
|
case Operator::Add: {
|
||||||
ObjectPtr lhs = eval(lexp, ctx);
|
ObjectPtr lhs = check_unwrap(eval(lexp, ctx));
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
|
||||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||||
{
|
{
|
||||||
@@ -46,8 +50,8 @@ namespace Fig
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
case Operator::Subtract: {
|
case Operator::Subtract: {
|
||||||
ObjectPtr lhs = eval(lexp, ctx);
|
ObjectPtr lhs = check_unwrap(eval(lexp, ctx));
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
|
||||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||||
{
|
{
|
||||||
@@ -58,8 +62,8 @@ namespace Fig
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
case Operator::Multiply: {
|
case Operator::Multiply: {
|
||||||
ObjectPtr lhs = eval(lexp, ctx);
|
ObjectPtr lhs = check_unwrap(eval(lexp, ctx));
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
|
||||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||||
{
|
{
|
||||||
@@ -70,13 +74,13 @@ namespace Fig
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
case Operator::Divide: {
|
case Operator::Divide: {
|
||||||
ObjectPtr lhs = eval(lexp, ctx);
|
ObjectPtr lhs = check_unwrap(eval(lexp, ctx));
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
|
||||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs / *rhs); });
|
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 = check_unwrap(eval(lexp, ctx));
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
|
||||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||||
{
|
{
|
||||||
@@ -93,8 +97,8 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
|
|
||||||
case Operator::Is: {
|
case Operator::Is: {
|
||||||
ObjectPtr lhs = eval(lexp, ctx);
|
ObjectPtr lhs = check_unwrap(eval(lexp, ctx));
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
|
||||||
|
|
||||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs, ctx, bin]() {
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs, ctx, bin]() {
|
||||||
const TypeInfo &lhsType = lhs->getTypeInfo();
|
const TypeInfo &lhsType = lhs->getTypeInfo();
|
||||||
@@ -143,9 +147,114 @@ namespace Fig
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Operator::As: {
|
||||||
|
ObjectPtr lhs = check_unwrap(eval(lexp, ctx));
|
||||||
|
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
|
||||||
|
|
||||||
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs, ctx, bin, this]() -> ExprResult {
|
||||||
|
if (!rhs->is<StructType>())
|
||||||
|
{
|
||||||
|
throw EvaluatorError(
|
||||||
|
u8"OperatorError",
|
||||||
|
std::format("Operator `as` requires right hand side operand a struct type, but got '{}'",
|
||||||
|
prettyType(rhs).toBasicString()),
|
||||||
|
bin->rexp);
|
||||||
|
}
|
||||||
|
const StructType &targetStructType = rhs->as<StructType>();
|
||||||
|
const TypeInfo &targetType = targetStructType.type;
|
||||||
|
const TypeInfo &sourceType = lhs->getTypeInfo();
|
||||||
|
if (targetType == sourceType) { return lhs; }
|
||||||
|
if (targetType == ValueType::String) { return std::make_shared<Object>(lhs->toStringIO()); }
|
||||||
|
if (sourceType == ValueType::Int)
|
||||||
|
{
|
||||||
|
if (targetType == ValueType::Double)
|
||||||
|
{
|
||||||
|
return std::make_shared<Object>(
|
||||||
|
static_cast<ValueType::DoubleClass>(lhs->as<ValueType::IntClass>()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (sourceType == ValueType::Double)
|
||||||
|
{
|
||||||
|
if (targetType == ValueType::Int)
|
||||||
|
{
|
||||||
|
return IntPool::getInstance().createInt(
|
||||||
|
static_cast<ValueType::IntClass>(lhs->as<ValueType::DoubleClass>()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (sourceType == ValueType::String)
|
||||||
|
{
|
||||||
|
const FString &str = lhs->as<ValueType::StringClass>();
|
||||||
|
if (targetType == ValueType::Int)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return IntPool::getInstance().createInt(
|
||||||
|
static_cast<ValueType::IntClass>(std::stoll(str.toBasicString())));
|
||||||
|
}
|
||||||
|
catch (std::exception &e)
|
||||||
|
{
|
||||||
|
return ExprResult::error(
|
||||||
|
genTypeError(FString(std::format("Cannot cast type `{}` to `{}`, bad int string {}",
|
||||||
|
prettyType(lhs).toBasicString(),
|
||||||
|
prettyType(rhs).toBasicString(),
|
||||||
|
str.toBasicString())),
|
||||||
|
bin->rexp,
|
||||||
|
ctx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (targetType == ValueType::Double)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return std::make_shared<Object>(std::stod(str.toBasicString()));
|
||||||
|
}
|
||||||
|
catch (std::exception &e)
|
||||||
|
{
|
||||||
|
return ExprResult::error(genTypeError(
|
||||||
|
FString(std::format("Cannot cast type `{}` to `{}`, bad double string {}",
|
||||||
|
prettyType(lhs).toBasicString(),
|
||||||
|
prettyType(rhs).toBasicString(),
|
||||||
|
str.toBasicString())),
|
||||||
|
bin->rexp,
|
||||||
|
ctx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (targetType == ValueType::Bool)
|
||||||
|
{
|
||||||
|
if (str == u8"true") { return Object::getTrueInstance(); }
|
||||||
|
else if (str == u8"false") { return Object::getFalseInstance(); }
|
||||||
|
return ExprResult::error(
|
||||||
|
genTypeError(FString(std::format("Cannot cast type `{}` to `{}`, bad bool string {}",
|
||||||
|
prettyType(lhs).toBasicString(),
|
||||||
|
prettyType(rhs).toBasicString(),
|
||||||
|
str.toBasicString())),
|
||||||
|
bin->rexp,
|
||||||
|
ctx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (sourceType == ValueType::Bool)
|
||||||
|
{
|
||||||
|
if (targetType == ValueType::Int)
|
||||||
|
{
|
||||||
|
return IntPool::getInstance().createInt(static_cast<ValueType::IntClass>(lhs->as<ValueType::BoolClass>()));
|
||||||
|
}
|
||||||
|
if (targetType == ValueType::Double)
|
||||||
|
{
|
||||||
|
return std::make_shared<Object>(static_cast<ValueType::DoubleClass>(lhs->as<ValueType::BoolClass>()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExprResult::error(genTypeError(FString(std::format("Cannot cast type `{}` to `{}`",
|
||||||
|
prettyType(lhs).toBasicString(),
|
||||||
|
prettyType(rhs).toBasicString())),
|
||||||
|
bin->rexp,
|
||||||
|
ctx));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
case Operator::BitAnd: {
|
case Operator::BitAnd: {
|
||||||
ObjectPtr lhs = eval(lexp, ctx);
|
ObjectPtr lhs = check_unwrap(eval(lexp, ctx));
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
|
||||||
|
|
||||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||||
@@ -156,9 +265,10 @@ namespace Fig
|
|||||||
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 = check_unwrap(eval(lexp, ctx));
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
|
||||||
|
|
||||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||||
@@ -169,9 +279,10 @@ namespace Fig
|
|||||||
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 = check_unwrap(eval(lexp, ctx));
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
|
||||||
|
|
||||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||||
@@ -182,9 +293,10 @@ namespace Fig
|
|||||||
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 = check_unwrap(eval(lexp, ctx));
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
|
||||||
|
|
||||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||||
@@ -196,8 +308,8 @@ namespace Fig
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
case Operator::ShiftRight: {
|
case Operator::ShiftRight: {
|
||||||
ObjectPtr lhs = eval(lexp, ctx);
|
ObjectPtr lhs = check_unwrap(eval(lexp, ctx));
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
|
||||||
|
|
||||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() {
|
||||||
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
if (lhs->is<ValueType::IntClass>() && rhs->is<ValueType::IntClass>())
|
||||||
@@ -210,99 +322,112 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
|
|
||||||
case Operator::Assign: {
|
case Operator::Assign: {
|
||||||
LvObject lv = evalLv(lexp, ctx);
|
LvObject lv = check_unwrap_lv(evalLv(lexp, ctx));
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
|
||||||
lv.set(rhs);
|
lv.set(rhs);
|
||||||
return rhs;
|
return rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Operator::And: {
|
case Operator::And: {
|
||||||
ObjectPtr lhs = eval(lexp, ctx);
|
ObjectPtr lhs = check_unwrap(eval(lexp, ctx));
|
||||||
if (lhs->is<bool>() && !isBoolObjectTruthy(lhs)) { return Object::getFalseInstance(); }
|
if (lhs->is<bool>() && !isBoolObjectTruthy(lhs)) { return Object::getFalseInstance(); }
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
|
||||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs && *rhs); });
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs && *rhs); });
|
||||||
}
|
}
|
||||||
|
|
||||||
case Operator::Or: {
|
case Operator::Or: {
|
||||||
ObjectPtr lhs = eval(lexp, ctx);
|
ObjectPtr lhs = check_unwrap(eval(lexp, ctx));
|
||||||
if (lhs->is<bool>() && isBoolObjectTruthy(lhs)) { return Object::getTrueInstance(); }
|
if (lhs->is<bool>() && isBoolObjectTruthy(lhs)) { return Object::getTrueInstance(); }
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
|
||||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs || *rhs); });
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs || *rhs); });
|
||||||
}
|
}
|
||||||
|
|
||||||
case Operator::Equal: {
|
case Operator::Equal: {
|
||||||
ObjectPtr lhs = eval(lexp, ctx);
|
ObjectPtr lhs = check_unwrap(eval(lexp, ctx));
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
|
||||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs == *rhs); });
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs == *rhs); });
|
||||||
}
|
}
|
||||||
|
|
||||||
case Operator::NotEqual: {
|
case Operator::NotEqual: {
|
||||||
ObjectPtr lhs = eval(lexp, ctx);
|
ObjectPtr lhs = check_unwrap(eval(lexp, ctx));
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
|
||||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs != *rhs); });
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs != *rhs); });
|
||||||
}
|
}
|
||||||
|
|
||||||
case Operator::Less: {
|
case Operator::Less: {
|
||||||
ObjectPtr lhs = eval(lexp, ctx);
|
ObjectPtr lhs = check_unwrap(eval(lexp, ctx));
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
|
||||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs < *rhs); });
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs < *rhs); });
|
||||||
}
|
}
|
||||||
|
|
||||||
case Operator::LessEqual: {
|
case Operator::LessEqual: {
|
||||||
ObjectPtr lhs = eval(lexp, ctx);
|
ObjectPtr lhs = check_unwrap(eval(lexp, ctx));
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
|
||||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs <= *rhs); });
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs <= *rhs); });
|
||||||
}
|
}
|
||||||
|
|
||||||
case Operator::Greater: {
|
case Operator::Greater: {
|
||||||
ObjectPtr lhs = eval(lexp, ctx);
|
ObjectPtr lhs = check_unwrap(eval(lexp, ctx));
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
|
||||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs > *rhs); });
|
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs > *rhs); });
|
||||||
}
|
}
|
||||||
|
|
||||||
case Operator::GreaterEqual: {
|
case Operator::GreaterEqual: {
|
||||||
ObjectPtr lhs = eval(lexp, ctx);
|
ObjectPtr lhs = check_unwrap(eval(lexp, ctx));
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
|
||||||
return tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs >= *rhs); });
|
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 = check_unwrap_lv(evalLv(lexp, ctx));
|
||||||
const ObjectPtr &lhs = lv.get();
|
const ObjectPtr &lhs = lv.get();
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
|
||||||
const ObjectPtr &result =
|
const ObjectPtr &result = check_unwrap(
|
||||||
tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs + *rhs); });
|
tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs + *rhs); }));
|
||||||
lv.set(result);
|
lv.set(result);
|
||||||
return rhs;
|
return rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Operator::MinusAssign: {
|
case Operator::MinusAssign: {
|
||||||
LvObject lv = evalLv(lexp, ctx);
|
LvObject lv = check_unwrap_lv(evalLv(lexp, ctx));
|
||||||
const ObjectPtr &lhs = lv.get();
|
const ObjectPtr &lhs = lv.get();
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
|
||||||
const ObjectPtr &result =
|
const ObjectPtr &result = check_unwrap(
|
||||||
tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs - *rhs); });
|
tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs - *rhs); }));
|
||||||
lv.set(result);
|
lv.set(result);
|
||||||
return rhs;
|
return rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Operator::AsteriskAssign: {
|
case Operator::AsteriskAssign: {
|
||||||
LvObject lv = evalLv(lexp, ctx);
|
LvObject lv = check_unwrap_lv(evalLv(lexp, ctx));
|
||||||
const ObjectPtr &lhs = lv.get();
|
const ObjectPtr &lhs = lv.get();
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
|
||||||
const ObjectPtr &result =
|
const ObjectPtr &result = check_unwrap(
|
||||||
tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs * *rhs); });
|
tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs * *rhs); }));
|
||||||
lv.set(result);
|
lv.set(result);
|
||||||
return rhs;
|
return rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Operator::SlashAssign: {
|
case Operator::SlashAssign: {
|
||||||
LvObject lv = evalLv(lexp, ctx);
|
LvObject lv = check_unwrap_lv(evalLv(lexp, ctx));
|
||||||
const ObjectPtr &lhs = lv.get();
|
const ObjectPtr &lhs = lv.get();
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
|
||||||
const ObjectPtr &result =
|
const ObjectPtr &result = check_unwrap(
|
||||||
tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs / *rhs); });
|
tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs / *rhs); }));
|
||||||
lv.set(result);
|
lv.set(result);
|
||||||
return rhs;
|
return rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Operator::PercentAssign: {
|
case Operator::PercentAssign: {
|
||||||
LvObject lv = evalLv(lexp, ctx);
|
LvObject lv = check_unwrap_lv(evalLv(lexp, ctx));
|
||||||
const ObjectPtr &lhs = lv.get();
|
const ObjectPtr &lhs = lv.get();
|
||||||
ObjectPtr rhs = eval(rexp, ctx);
|
ObjectPtr rhs = check_unwrap(eval(rexp, ctx));
|
||||||
const ObjectPtr &result =
|
const ObjectPtr &result = check_unwrap(
|
||||||
tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs % *rhs); });
|
tryInvokeOverloadFn(lhs, rhs, [lhs, rhs]() { return std::make_shared<Object>(*lhs % *rhs); }));
|
||||||
lv.set(result);
|
lv.set(result);
|
||||||
return rhs;
|
return 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)),
|
||||||
|
|||||||
@@ -5,10 +5,11 @@
|
|||||||
#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 <Evaluator/Core/ExprResult.hpp>
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
RvObject Evaluator::executeFunction(const Function &fn,
|
ExprResult Evaluator::executeFunction(const Function &fn,
|
||||||
const Ast::FunctionCallArgs &args,
|
const Ast::FunctionCallArgs &args,
|
||||||
ContextPtr fnCtx) // new context for fn, already filled paras
|
ContextPtr fnCtx) // new context for fn, already filled paras
|
||||||
{
|
{
|
||||||
@@ -28,9 +29,7 @@ namespace Fig
|
|||||||
StatementResult sr = evalStatement(stmt, fnCtx);
|
StatementResult sr = evalStatement(stmt, fnCtx);
|
||||||
if (sr.isError())
|
if (sr.isError())
|
||||||
{
|
{
|
||||||
throw EvaluatorError(u8"UncaughtExceptionError",
|
handle_error(sr, stmt, fnCtx);
|
||||||
std::format("Uncaught exception: {}", sr.result->toString().toBasicString()),
|
|
||||||
stmt);
|
|
||||||
}
|
}
|
||||||
if (!sr.isNormal())
|
if (!sr.isNormal())
|
||||||
{
|
{
|
||||||
@@ -39,9 +38,9 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
return Object::getNullInstance();
|
return Object::getNullInstance();
|
||||||
}
|
}
|
||||||
RvObject Evaluator::evalFunctionCall(const Ast::FunctionCall &call, ContextPtr ctx)
|
ExprResult Evaluator::evalFunctionCall(const Ast::FunctionCall &call, ContextPtr ctx)
|
||||||
{
|
{
|
||||||
RvObject fnObj = eval(call->callee, ctx);
|
RvObject fnObj = check_unwrap(eval(call->callee, ctx));
|
||||||
if (fnObj->getTypeInfo() != ValueType::Function)
|
if (fnObj->getTypeInfo() != ValueType::Function)
|
||||||
{
|
{
|
||||||
throw EvaluatorError(u8"ObjectNotCallable",
|
throw EvaluatorError(u8"ObjectNotCallable",
|
||||||
@@ -57,7 +56,7 @@ namespace Fig
|
|||||||
Ast::FunctionCallArgs evaluatedArgs;
|
Ast::FunctionCallArgs evaluatedArgs;
|
||||||
if (fn.type == Function::Builtin || fn.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(check_unwrap(eval(argExpr, ctx))); }
|
||||||
if (fn.builtinParamCount != -1 && fn.builtinParamCount != evaluatedArgs.getLength())
|
if (fn.builtinParamCount != -1 && fn.builtinParamCount != evaluatedArgs.getLength())
|
||||||
{
|
{
|
||||||
throw EvaluatorError(u8"BuiltinArgumentMismatchError",
|
throw EvaluatorError(u8"BuiltinArgumentMismatchError",
|
||||||
@@ -96,9 +95,9 @@ namespace Fig
|
|||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < fnParas.posParas.size(); i++)
|
for (i = 0; i < fnParas.posParas.size(); i++)
|
||||||
{
|
{
|
||||||
const TypeInfo &expectedType = actualType(eval(fnParas.posParas[i].second, fn.closureContext)); // look up type info, if exists a type
|
const TypeInfo &expectedType = actualType(check_unwrap(eval(fnParas.posParas[i].second, fn.closureContext))); // look up type info, if exists a type
|
||||||
// with the name, use it, else throw
|
// with the name, use it, else throw
|
||||||
ObjectPtr argVal = eval(fnArgs.argv[i], ctx);
|
ObjectPtr argVal = check_unwrap(eval(fnArgs.argv[i], ctx));
|
||||||
TypeInfo actualType = argVal->getTypeInfo();
|
TypeInfo actualType = argVal->getTypeInfo();
|
||||||
if (!isTypeMatch(expectedType, argVal, fn.closureContext))
|
if (!isTypeMatch(expectedType, argVal, fn.closureContext))
|
||||||
{
|
{
|
||||||
@@ -116,9 +115,10 @@ 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();
|
||||||
const TypeInfo &expectedType = actualType(eval(fnParas.defParas[defParamIndex].second.first, fn.closureContext));
|
const TypeInfo &expectedType =
|
||||||
|
actualType(check_unwrap(eval(fnParas.defParas[defParamIndex].second.first, fn.closureContext)));
|
||||||
|
|
||||||
ObjectPtr defaultVal = eval(fnParas.defParas[defParamIndex].second.second, fn.closureContext);
|
ObjectPtr defaultVal = check_unwrap(eval(fnParas.defParas[defParamIndex].second.second, fn.closureContext));
|
||||||
if (!isTypeMatch(expectedType, defaultVal, fn.closureContext))
|
if (!isTypeMatch(expectedType, defaultVal, fn.closureContext))
|
||||||
{
|
{
|
||||||
throw EvaluatorError(
|
throw EvaluatorError(
|
||||||
@@ -132,7 +132,7 @@ namespace Fig
|
|||||||
fnArgs.argv[i]);
|
fnArgs.argv[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectPtr argVal = eval(fnArgs.argv[i], ctx);
|
ObjectPtr argVal = check_unwrap(eval(fnArgs.argv[i], ctx));
|
||||||
TypeInfo actualType = argVal->getTypeInfo();
|
TypeInfo actualType = argVal->getTypeInfo();
|
||||||
if (!isTypeMatch(expectedType, argVal, fn.closureContext))
|
if (!isTypeMatch(expectedType, argVal, fn.closureContext))
|
||||||
{
|
{
|
||||||
@@ -150,7 +150,7 @@ namespace Fig
|
|||||||
for (; i < fnParas.size(); i++)
|
for (; i < fnParas.size(); i++)
|
||||||
{
|
{
|
||||||
size_t defParamIndex = i - fnParas.posParas.size();
|
size_t defParamIndex = i - fnParas.posParas.size();
|
||||||
ObjectPtr defaultVal = eval(fnParas.defParas[defParamIndex].second.second, fn.closureContext);
|
ObjectPtr defaultVal = check_unwrap(eval(fnParas.defParas[defParamIndex].second.second, fn.closureContext));
|
||||||
evaluatedArgs.argv.push_back(defaultVal);
|
evaluatedArgs.argv.push_back(defaultVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,13 +162,14 @@ namespace Fig
|
|||||||
if (j < fnParas.posParas.size())
|
if (j < fnParas.posParas.size())
|
||||||
{
|
{
|
||||||
paramName = fnParas.posParas[j].first;
|
paramName = fnParas.posParas[j].first;
|
||||||
paramType = actualType(eval(fnParas.posParas[j].second, fn.closureContext));
|
paramType = actualType(check_unwrap(eval(fnParas.posParas[j].second, fn.closureContext)));
|
||||||
}
|
}
|
||||||
else
|
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 = actualType(eval(fnParas.defParas[defParamIndex].second.first, fn.closureContext));
|
paramType =
|
||||||
|
actualType(check_unwrap(eval(fnParas.defParas[defParamIndex].second.first, fn.closureContext)));
|
||||||
}
|
}
|
||||||
AccessModifier argAm = AccessModifier::Normal;
|
AccessModifier argAm = AccessModifier::Normal;
|
||||||
newContext->def(paramName, paramType, argAm, evaluatedArgs.argv[j]);
|
newContext->def(paramName, paramType, argAm, evaluatedArgs.argv[j]);
|
||||||
@@ -180,7 +181,7 @@ namespace Fig
|
|||||||
List list;
|
List list;
|
||||||
for (auto &exp : fnArgs.argv)
|
for (auto &exp : fnArgs.argv)
|
||||||
{
|
{
|
||||||
list.push_back(eval(exp, ctx)); // eval arguments in current scope
|
list.push_back(check_unwrap(eval(exp, ctx))); // eval arguments in current scope
|
||||||
}
|
}
|
||||||
newContext->def(fnParas.variadicPara, ValueType::List, AccessModifier::Normal, std::make_shared<Object>(list));
|
newContext->def(fnParas.variadicPara, ValueType::List, AccessModifier::Normal, std::make_shared<Object>(list));
|
||||||
goto ExecuteBody;
|
goto ExecuteBody;
|
||||||
@@ -188,7 +189,7 @@ namespace Fig
|
|||||||
|
|
||||||
ExecuteBody: {
|
ExecuteBody: {
|
||||||
// execute function body
|
// execute function body
|
||||||
ObjectPtr retVal = executeFunction(fn, evaluatedArgs, newContext);
|
ObjectPtr retVal = check_unwrap(executeFunction(fn, evaluatedArgs, newContext));
|
||||||
|
|
||||||
if (!isTypeMatch(fn.retType, retVal, ctx))
|
if (!isTypeMatch(fn.retType, retVal, ctx))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include <Evaluator/Core/ExprResult.hpp>
|
||||||
#include <Evaluator/Value/value.hpp>
|
#include <Evaluator/Value/value.hpp>
|
||||||
#include <Evaluator/Value/LvObject.hpp>
|
#include <Evaluator/Value/LvObject.hpp>
|
||||||
#include <Evaluator/evaluator.hpp>
|
#include <Evaluator/evaluator.hpp>
|
||||||
@@ -5,9 +6,9 @@
|
|||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
RvObject Evaluator::evalInitExpr(Ast::InitExpr initExpr, ContextPtr ctx)
|
ExprResult Evaluator::evalInitExpr(Ast::InitExpr initExpr, ContextPtr ctx)
|
||||||
{
|
{
|
||||||
LvObject structeLv = evalLv(initExpr->structe, ctx);
|
LvObject structeLv = check_unwrap_lv(evalLv(initExpr->structe, ctx));
|
||||||
ObjectPtr structTypeVal = structeLv.get();
|
ObjectPtr structTypeVal = structeLv.get();
|
||||||
const FString &structName = structeLv.name();
|
const FString &structName = structeLv.name();
|
||||||
if (!structTypeVal->is<StructType>())
|
if (!structTypeVal->is<StructType>())
|
||||||
@@ -46,7 +47,7 @@ namespace Fig
|
|||||||
return std::make_shared<Object>(Object::defaultValue(type));
|
return std::make_shared<Object>(Object::defaultValue(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectPtr val = eval(args[0].second, ctx);
|
ObjectPtr val = check_unwrap(eval(args[0].second, ctx));
|
||||||
|
|
||||||
auto err = [&](const char *msg) {
|
auto err = [&](const char *msg) {
|
||||||
throw EvaluatorError(u8"BuiltinInitTypeMismatchError",
|
throw EvaluatorError(u8"BuiltinInitTypeMismatchError",
|
||||||
@@ -153,8 +154,9 @@ namespace Fig
|
|||||||
auto evalArguments = [&evaluatedArgs, initExpr, ctx, this](){
|
auto evalArguments = [&evaluatedArgs, initExpr, ctx, this](){
|
||||||
for (const auto &[argName, argExpr] : initExpr->args)
|
for (const auto &[argName, argExpr] : initExpr->args)
|
||||||
{
|
{
|
||||||
evaluatedArgs.push_back({argName, eval(argExpr, ctx)});
|
evaluatedArgs.push_back({argName, check_unwrap(eval(argExpr, ctx))});
|
||||||
}
|
}
|
||||||
|
return ExprResult::normal(Object::getNullInstance());
|
||||||
};
|
};
|
||||||
|
|
||||||
ContextPtr instanceCtx =
|
ContextPtr instanceCtx =
|
||||||
@@ -182,8 +184,8 @@ namespace Fig
|
|||||||
// must be a default value
|
// must be a default value
|
||||||
|
|
||||||
// evaluate default value in definition context
|
// evaluate default value in definition context
|
||||||
ObjectPtr defaultVal = eval(field.defaultValue,
|
ObjectPtr defaultVal = check_unwrap(eval(field.defaultValue,
|
||||||
ctx); // it can't be null here
|
ctx)); // it can't be null here
|
||||||
|
|
||||||
// type check
|
// type check
|
||||||
if (!isTypeMatch(expectedType, defaultVal, ctx))
|
if (!isTypeMatch(expectedType, defaultVal, ctx))
|
||||||
@@ -238,8 +240,8 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
// use default value //
|
// use default value //
|
||||||
// evaluate default value in definition context
|
// evaluate default value in definition context
|
||||||
ObjectPtr defaultVal = eval(field.defaultValue,
|
ObjectPtr defaultVal = check_unwrap(eval(field.defaultValue,
|
||||||
defContext); // it can't be null here
|
defContext)); // it can't be null here
|
||||||
|
|
||||||
// type check
|
// type check
|
||||||
const TypeInfo &expectedType = field.type;
|
const TypeInfo &expectedType = field.type;
|
||||||
@@ -282,7 +284,7 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
// assert(argExpr->getType() == Ast::AstType::VarExpr);
|
// assert(argExpr->getType() == Ast::AstType::VarExpr);
|
||||||
// argName is var name
|
// argName is var name
|
||||||
const ObjectPtr &argVal = eval(argExpr, ctx); // get the value
|
const ObjectPtr &argVal = check_unwrap(eval(argExpr, ctx)); // get the value
|
||||||
// find field
|
// find field
|
||||||
auto fieldIt = std::find_if(structT.fields.begin(),
|
auto fieldIt = std::find_if(structT.fields.begin(),
|
||||||
structT.fields.end(),
|
structT.fields.end(),
|
||||||
@@ -323,8 +325,8 @@ namespace Fig
|
|||||||
const Field &field = structT.fields[i];
|
const Field &field = structT.fields[i];
|
||||||
|
|
||||||
// evaluate default value in definition context
|
// evaluate default value in definition context
|
||||||
ObjectPtr defaultVal = eval(field.defaultValue,
|
ObjectPtr defaultVal = check_unwrap(eval(field.defaultValue,
|
||||||
defContext); // it can't be null here
|
defContext)); // it can't be null here
|
||||||
|
|
||||||
// type check
|
// type check
|
||||||
if (!isTypeMatch(field.type, defaultVal, ctx))
|
if (!isTypeMatch(field.type, defaultVal, ctx))
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include "Evaluator/Core/ExprResult.hpp"
|
||||||
#include <Evaluator/Value/value.hpp>
|
#include <Evaluator/Value/value.hpp>
|
||||||
#include <Evaluator/Value/LvObject.hpp>
|
#include <Evaluator/Value/LvObject.hpp>
|
||||||
#include <Evaluator/evaluator.hpp>
|
#include <Evaluator/evaluator.hpp>
|
||||||
@@ -5,7 +6,7 @@
|
|||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
LvObject Evaluator::evalVarExpr(Ast::VarExpr var, ContextPtr ctx)
|
ExprResult Evaluator::evalVarExpr(Ast::VarExpr var, ContextPtr ctx)
|
||||||
{
|
{
|
||||||
const FString &name = var->name;
|
const FString &name = var->name;
|
||||||
|
|
||||||
@@ -40,10 +41,10 @@ namespace Fig
|
|||||||
if (!ctx->contains(name)) { throw EvaluatorError(u8"UndeclaredIdentifierError", name, var); }
|
if (!ctx->contains(name)) { throw EvaluatorError(u8"UndeclaredIdentifierError", name, var); }
|
||||||
return LvObject(ctx->get(name), ctx);
|
return LvObject(ctx->get(name), ctx);
|
||||||
}
|
}
|
||||||
LvObject Evaluator::evalMemberExpr(Ast::MemberExpr me, ContextPtr ctx)
|
ExprResult Evaluator::evalMemberExpr(Ast::MemberExpr me, ContextPtr ctx)
|
||||||
{
|
{
|
||||||
// LvObject base = evalLv(me->base, ctx);
|
// LvObject base = evalLv(me->base, ctx);
|
||||||
RvObject baseVal = eval(me->base, ctx);
|
RvObject baseVal = check_unwrap(eval(me->base, ctx));
|
||||||
const FString &member = me->member;
|
const FString &member = me->member;
|
||||||
if (baseVal->getTypeInfo() == ValueType::Module)
|
if (baseVal->getTypeInfo() == ValueType::Module)
|
||||||
{
|
{
|
||||||
@@ -144,7 +145,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(member, ifm.paras, actualType(eval(ifm.returnType, ctx)), ifm.defaultBody, ctx);
|
Function fn(member, ifm.paras, actualType(check_unwrap(eval(ifm.returnType, ctx))), ifm.defaultBody, ctx);
|
||||||
|
|
||||||
return LvObject(std::make_shared<VariableSlot>(
|
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),
|
||||||
@@ -159,10 +160,10 @@ namespace Fig
|
|||||||
me->base);
|
me->base);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LvObject Evaluator::evalIndexExpr(Ast::IndexExpr ie, ContextPtr ctx)
|
ExprResult Evaluator::evalIndexExpr(Ast::IndexExpr ie, ContextPtr ctx)
|
||||||
{
|
{
|
||||||
RvObject base = eval(ie->base, ctx);
|
RvObject base = check_unwrap(eval(ie->base, ctx));
|
||||||
RvObject index = eval(ie->index, ctx);
|
RvObject index = check_unwrap(eval(ie->index, ctx));
|
||||||
|
|
||||||
const TypeInfo &type = base.get()->getTypeInfo();
|
const TypeInfo &type = base.get()->getTypeInfo();
|
||||||
|
|
||||||
@@ -215,7 +216,7 @@ namespace Fig
|
|||||||
ie->base);
|
ie->base);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LvObject Evaluator::evalLv(Ast::Expression exp, ContextPtr ctx)
|
ExprResult Evaluator::evalLv(Ast::Expression exp, ContextPtr ctx)
|
||||||
{
|
{
|
||||||
using Ast::Operator;
|
using Ast::Operator;
|
||||||
using Ast::AstType;
|
using Ast::AstType;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include "Evaluator/Core/ExprResult.hpp"
|
||||||
#include <Ast/AccessModifier.hpp>
|
#include <Ast/AccessModifier.hpp>
|
||||||
#include <Ast/Expressions/FunctionCall.hpp>
|
#include <Ast/Expressions/FunctionCall.hpp>
|
||||||
#include <Ast/astBase.hpp>
|
#include <Ast/astBase.hpp>
|
||||||
@@ -37,7 +38,7 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
|
|
||||||
RvObject value = nullptr;
|
RvObject value = nullptr;
|
||||||
if (varDef->expr) { value = eval(varDef->expr, ctx); }
|
if (varDef->expr) { value = check_unwrap_stres(eval(varDef->expr, ctx)); }
|
||||||
|
|
||||||
TypeInfo declaredType; // default is Any
|
TypeInfo declaredType; // default is Any
|
||||||
const Ast::Expression &declaredTypeExp = varDef->declaredType;
|
const Ast::Expression &declaredTypeExp = varDef->declaredType;
|
||||||
@@ -45,7 +46,7 @@ namespace Fig
|
|||||||
if (varDef->followupType) { declaredType = actualType(value); }
|
if (varDef->followupType) { declaredType = actualType(value); }
|
||||||
else if (declaredTypeExp)
|
else if (declaredTypeExp)
|
||||||
{
|
{
|
||||||
ObjectPtr declaredTypeValue = eval(declaredTypeExp, ctx);
|
ObjectPtr declaredTypeValue = check_unwrap_stres(eval(declaredTypeExp, ctx));
|
||||||
declaredType = actualType(declaredTypeValue);
|
declaredType = actualType(declaredTypeValue);
|
||||||
|
|
||||||
if (value != nullptr && !isTypeMatch(declaredType, value, ctx))
|
if (value != nullptr && !isTypeMatch(declaredType, value, ctx))
|
||||||
@@ -83,7 +84,7 @@ namespace Fig
|
|||||||
TypeInfo returnType = ValueType::Any;
|
TypeInfo returnType = ValueType::Any;
|
||||||
if (fnDef->retType)
|
if (fnDef->retType)
|
||||||
{
|
{
|
||||||
ObjectPtr returnTypeValue = eval(fnDef->retType, ctx);
|
ObjectPtr returnTypeValue = check_unwrap_stres(eval(fnDef->retType, ctx));
|
||||||
returnType = actualType(returnTypeValue);
|
returnType = actualType(returnTypeValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +118,10 @@ namespace Fig
|
|||||||
AccessModifier am = (stDef->isPublic ? AccessModifier::PublicConst : AccessModifier::Const);
|
AccessModifier am = (stDef->isPublic ? AccessModifier::PublicConst : AccessModifier::Const);
|
||||||
|
|
||||||
ctx->def(stDef->name, ValueType::StructType, am, structTypeObj); // predef
|
ctx->def(stDef->name, ValueType::StructType, am, structTypeObj); // predef
|
||||||
defContext->def(stDef->name, ValueType::StructType, AccessModifier::Const, structTypeObj); // predef to itself, always const
|
defContext->def(stDef->name,
|
||||||
|
ValueType::StructType,
|
||||||
|
AccessModifier::Const,
|
||||||
|
structTypeObj); // predef to itself, always const
|
||||||
|
|
||||||
std::vector<Field> fields;
|
std::vector<Field> fields;
|
||||||
std::vector<FString> _fieldNames;
|
std::vector<FString> _fieldNames;
|
||||||
@@ -134,7 +138,7 @@ namespace Fig
|
|||||||
TypeInfo fieldType = ValueType::Any;
|
TypeInfo fieldType = ValueType::Any;
|
||||||
if (field.declaredType)
|
if (field.declaredType)
|
||||||
{
|
{
|
||||||
ObjectPtr declaredTypeValue = eval(field.declaredType, ctx);
|
ObjectPtr declaredTypeValue = check_unwrap_stres(eval(field.declaredType, ctx));
|
||||||
fieldType = actualType(declaredTypeValue);
|
fieldType = actualType(declaredTypeValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,11 +243,10 @@ namespace Fig
|
|||||||
*/
|
*/
|
||||||
if (ValueType::isTypeBuiltin(structType))
|
if (ValueType::isTypeBuiltin(structType))
|
||||||
{
|
{
|
||||||
throw EvaluatorError(
|
throw EvaluatorError(u8"BadUserError",
|
||||||
u8"BadUserError",
|
std::format("Don't overload built-in type operators plz! `{}`",
|
||||||
std::format("Don't overload built-in type operators plz! `{}`", prettyType(structTypeObj).toBasicString()),
|
prettyType(structTypeObj).toBasicString()),
|
||||||
ip
|
ip);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
using enum Ast::Operator;
|
using enum Ast::Operator;
|
||||||
@@ -328,7 +331,8 @@ namespace Fig
|
|||||||
const Ast::FunctionParameters ¶s = implMethod.paras;
|
const Ast::FunctionParameters ¶s = implMethod.paras;
|
||||||
for (size_t i = 0; i < paraCnt; ++i)
|
for (size_t i = 0; i < paraCnt; ++i)
|
||||||
{
|
{
|
||||||
const TypeInfo ¶Type = actualType(eval(paras.posParas[i].second, ctx));
|
const TypeInfo ¶Type =
|
||||||
|
actualType(check_unwrap_stres(eval(paras.posParas[i].second, ctx)));
|
||||||
if (paraType != ValueType::Any && paraType != structType)
|
if (paraType != ValueType::Any && paraType != structType)
|
||||||
{
|
{
|
||||||
throw EvaluatorError(
|
throw EvaluatorError(
|
||||||
@@ -345,7 +349,7 @@ namespace Fig
|
|||||||
|
|
||||||
if (paraCnt == 1)
|
if (paraCnt == 1)
|
||||||
{
|
{
|
||||||
ctx->registerUnaryOperator(structType, op, [=, this](const ObjectPtr &value) -> ObjectPtr {
|
ctx->registerUnaryOperator(structType, op, [=, this](const ObjectPtr &value) -> ExprResult {
|
||||||
fillOpFnParas({value});
|
fillOpFnParas({value});
|
||||||
return executeFunction(Function(opFnName,
|
return executeFunction(Function(opFnName,
|
||||||
implMethod.paras, // parameters
|
implMethod.paras, // parameters
|
||||||
@@ -447,7 +451,7 @@ namespace Fig
|
|||||||
|
|
||||||
implemented.insert(name);
|
implemented.insert(name);
|
||||||
|
|
||||||
ObjectPtr returnTypeValue = eval(ifMethod.returnType, ctx);
|
ObjectPtr returnTypeValue = check_unwrap_stres(eval(ifMethod.returnType, ctx));
|
||||||
|
|
||||||
record.implMethods[name] =
|
record.implMethods[name] =
|
||||||
Function(implMethod.name, implMethod.paras, actualType(returnTypeValue), implMethod.body, ctx);
|
Function(implMethod.name, implMethod.paras, actualType(returnTypeValue), implMethod.body, ctx);
|
||||||
@@ -474,7 +478,7 @@ namespace Fig
|
|||||||
|
|
||||||
case IfSt: {
|
case IfSt: {
|
||||||
auto ifSt = std::static_pointer_cast<Ast::IfSt>(stmt);
|
auto ifSt = std::static_pointer_cast<Ast::IfSt>(stmt);
|
||||||
ObjectPtr condVal = eval(ifSt->condition, ctx);
|
ObjectPtr condVal = check_unwrap_stres(eval(ifSt->condition, ctx));
|
||||||
if (condVal->getTypeInfo() != ValueType::Bool)
|
if (condVal->getTypeInfo() != ValueType::Bool)
|
||||||
{
|
{
|
||||||
throw EvaluatorError(
|
throw EvaluatorError(
|
||||||
@@ -486,7 +490,7 @@ namespace Fig
|
|||||||
// else
|
// else
|
||||||
for (const auto &elif : ifSt->elifs)
|
for (const auto &elif : ifSt->elifs)
|
||||||
{
|
{
|
||||||
ObjectPtr elifCondVal = eval(elif->condition, ctx);
|
ObjectPtr elifCondVal = check_unwrap_stres(eval(elif->condition, ctx));
|
||||||
if (elifCondVal->getTypeInfo() != ValueType::Bool)
|
if (elifCondVal->getTypeInfo() != ValueType::Bool)
|
||||||
{
|
{
|
||||||
throw EvaluatorError(
|
throw EvaluatorError(
|
||||||
@@ -503,7 +507,7 @@ namespace Fig
|
|||||||
auto whileSt = std::static_pointer_cast<Ast::WhileSt>(stmt);
|
auto whileSt = std::static_pointer_cast<Ast::WhileSt>(stmt);
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
ObjectPtr condVal = eval(whileSt->condition, ctx);
|
ObjectPtr condVal = check_unwrap_stres(eval(whileSt->condition, ctx));
|
||||||
if (condVal->getTypeInfo() != ValueType::Bool)
|
if (condVal->getTypeInfo() != ValueType::Bool)
|
||||||
{
|
{
|
||||||
throw EvaluatorError(
|
throw EvaluatorError(
|
||||||
@@ -535,7 +539,7 @@ namespace Fig
|
|||||||
while (true) // use while loop to simulate for loop, cause we
|
while (true) // use while loop to simulate for loop, cause we
|
||||||
// need to check condition type every iteration
|
// need to check condition type every iteration
|
||||||
{
|
{
|
||||||
ObjectPtr condVal = eval(forSt->condition, loopContext);
|
ObjectPtr condVal = check_unwrap_stres(eval(forSt->condition, loopContext));
|
||||||
if (condVal->getTypeInfo() != ValueType::Bool)
|
if (condVal->getTypeInfo() != ValueType::Bool)
|
||||||
{
|
{
|
||||||
throw EvaluatorError(
|
throw EvaluatorError(
|
||||||
@@ -569,10 +573,15 @@ namespace Fig
|
|||||||
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();
|
||||||
|
bool crashed = false;
|
||||||
for (auto &stmt : tryst->body->stmts)
|
for (auto &stmt : tryst->body->stmts)
|
||||||
{
|
{
|
||||||
sr = evalStatement(stmt, tryCtx); // eval in try context
|
sr = evalStatement(stmt, tryCtx); // eval in try context
|
||||||
if (sr.isError()) { break; }
|
if (sr.isError())
|
||||||
|
{
|
||||||
|
crashed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
bool catched = false;
|
bool catched = false;
|
||||||
for (auto &cat : tryst->catches)
|
for (auto &cat : tryst->catches)
|
||||||
@@ -591,7 +600,7 @@ namespace Fig
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!catched)
|
if (!catched && crashed)
|
||||||
{
|
{
|
||||||
throw EvaluatorError(u8"UncaughtExceptionError",
|
throw EvaluatorError(u8"UncaughtExceptionError",
|
||||||
std::format("Uncaught exception: {}", sr.result->toString().toBasicString()),
|
std::format("Uncaught exception: {}", sr.result->toString().toBasicString()),
|
||||||
@@ -604,7 +613,7 @@ 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 = check_unwrap_stres(eval(ts->value, ctx));
|
||||||
if (value->is<ValueType::NullClass>())
|
if (value->is<ValueType::NullClass>())
|
||||||
{
|
{
|
||||||
throw EvaluatorError(u8"TypeError", u8"Why did you throw a null?", ts);
|
throw EvaluatorError(u8"TypeError", u8"Why did you throw a null?", ts);
|
||||||
@@ -616,7 +625,7 @@ namespace Fig
|
|||||||
auto returnSt = std::static_pointer_cast<Ast::ReturnSt>(stmt);
|
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 = check_unwrap_stres(eval(returnSt->retValue, ctx));
|
||||||
return StatementResult::returnFlow(returnValue);
|
return StatementResult::returnFlow(returnValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -646,7 +655,7 @@ namespace Fig
|
|||||||
|
|
||||||
case ExpressionStmt: {
|
case ExpressionStmt: {
|
||||||
auto exprStmt = std::static_pointer_cast<Ast::ExpressionStmtAst>(stmt);
|
auto exprStmt = std::static_pointer_cast<Ast::ExpressionStmtAst>(stmt);
|
||||||
return StatementResult::normal(eval(exprStmt->exp, ctx));
|
return check_unwrap_stres(eval(exprStmt->exp, ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
case BlockStatement: {
|
case BlockStatement: {
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
#include <Evaluator/evaluator.hpp>
|
#include <Evaluator/evaluator.hpp>
|
||||||
#include <Evaluator/evaluator_error.hpp>
|
#include <Evaluator/evaluator_error.hpp>
|
||||||
|
#include <Evaluator/Core/ExprResult.hpp>
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
|
|
||||||
RvObject Evaluator::evalTernary(Ast::TernaryExpr te, ContextPtr ctx)
|
ExprResult Evaluator::evalTernary(Ast::TernaryExpr te, ContextPtr ctx)
|
||||||
{
|
{
|
||||||
RvObject condVal = eval(te->condition, ctx);
|
RvObject condVal = check_unwrap(eval(te->condition, ctx));
|
||||||
if (condVal->getTypeInfo() != ValueType::Bool)
|
if (condVal->getTypeInfo() != ValueType::Bool)
|
||||||
{
|
{
|
||||||
throw EvaluatorError(
|
throw EvaluatorError(
|
||||||
|
|||||||
@@ -2,17 +2,18 @@
|
|||||||
#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 <Evaluator/Core/ExprResult.hpp>
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
RvObject Evaluator::evalUnary(Ast::UnaryExpr un, ContextPtr ctx)
|
ExprResult Evaluator::evalUnary(Ast::UnaryExpr un, ContextPtr ctx)
|
||||||
{
|
{
|
||||||
using Ast::Operator;
|
using Ast::Operator;
|
||||||
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 = check_unwrap(eval(exp, ctx));
|
||||||
|
|
||||||
const auto &tryInvokeOverloadFn = [ctx, op](const ObjectPtr &rhs, const std::function<ObjectPtr()> &rollback) {
|
const auto &tryInvokeOverloadFn = [ctx, op](const ObjectPtr &rhs, const std::function<ExprResult()> &rollback) {
|
||||||
if (rhs->is<StructInstance>())
|
if (rhs->is<StructInstance>())
|
||||||
{
|
{
|
||||||
// 运算符重载
|
// 运算符重载
|
||||||
|
|||||||
19
src/Evaluator/Core/ExprResult.cpp
Normal file
19
src/Evaluator/Core/ExprResult.cpp
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#include <Evaluator/Core/ExprResult.hpp>
|
||||||
|
#include <Evaluator/Core/StatementResult.hpp>
|
||||||
|
|
||||||
|
namespace Fig
|
||||||
|
{
|
||||||
|
StatementResult ExprResult::toStatementResult() const
|
||||||
|
{
|
||||||
|
if (isError())
|
||||||
|
{
|
||||||
|
if (isResultLv())
|
||||||
|
{
|
||||||
|
return StatementResult::errorFlow(std::get<LvObject>(result).get());
|
||||||
|
}
|
||||||
|
return StatementResult::errorFlow(std::get<RvObject>(result));
|
||||||
|
}
|
||||||
|
if (isResultLv()) { return StatementResult::normal(std::get<LvObject>(result).get()); }
|
||||||
|
return StatementResult::normal(std::get<RvObject>(result));
|
||||||
|
}
|
||||||
|
};
|
||||||
72
src/Evaluator/Core/ExprResult.hpp
Normal file
72
src/Evaluator/Core/ExprResult.hpp
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Core/fig_string.hpp>
|
||||||
|
#include <Evaluator/Value/value_forward.hpp>
|
||||||
|
#include <Evaluator/Value/LvObject.hpp>
|
||||||
|
|
||||||
|
#include <variant>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace Fig
|
||||||
|
{
|
||||||
|
struct StatementResult;
|
||||||
|
struct ExprResult
|
||||||
|
{
|
||||||
|
std::variant<LvObject, RvObject> result;
|
||||||
|
enum class Flow
|
||||||
|
{
|
||||||
|
Normal,
|
||||||
|
Error,
|
||||||
|
} flow;
|
||||||
|
|
||||||
|
ExprResult(ObjectPtr _result, Flow _flow = Flow::Normal) : result(_result), flow(_flow) {}
|
||||||
|
ExprResult(const LvObject &_result, Flow _flow = Flow::Normal) : result(_result), flow(_flow) {}
|
||||||
|
|
||||||
|
static ExprResult normal(ObjectPtr _result) { return ExprResult(_result); }
|
||||||
|
static ExprResult normal(const LvObject &_result) { return ExprResult(_result); }
|
||||||
|
|
||||||
|
static ExprResult error(ObjectPtr _result) { return ExprResult(_result, Flow::Error); }
|
||||||
|
static ExprResult error(const LvObject &_result) { return ExprResult(_result, Flow::Error); }
|
||||||
|
|
||||||
|
bool isNormal() const { return flow == Flow::Normal; }
|
||||||
|
|
||||||
|
bool isError() const { return flow == Flow::Error; }
|
||||||
|
|
||||||
|
bool isResultLv() const { return std::holds_alternative<LvObject>(result); }
|
||||||
|
|
||||||
|
ObjectPtr &unwrap()
|
||||||
|
{
|
||||||
|
if (!isNormal()) { assert(false && "unwrap abnormal ExprResult!"); }
|
||||||
|
return std::get<RvObject>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ObjectPtr &unwrap() const
|
||||||
|
{
|
||||||
|
if (!isNormal()) { assert(false && "unwrap abnormal ExprResult!"); }
|
||||||
|
return std::get<RvObject>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
const LvObject &unwrap_lv() const { return std::get<LvObject>(result); }
|
||||||
|
|
||||||
|
StatementResult toStatementResult() const;
|
||||||
|
};
|
||||||
|
#define check_unwrap(expr) \
|
||||||
|
({ \
|
||||||
|
auto _r = (expr); \
|
||||||
|
if (_r.isError()) return _r; \
|
||||||
|
_r.unwrap(); \
|
||||||
|
})
|
||||||
|
#define check_unwrap_lv(expr) \
|
||||||
|
({ \
|
||||||
|
auto _r = (expr); \
|
||||||
|
if (_r.isError()) return _r; \
|
||||||
|
_r.unwrap_lv(); \
|
||||||
|
})
|
||||||
|
#define check_unwrap_stres(expr) \
|
||||||
|
({ \
|
||||||
|
auto _r = (expr); \
|
||||||
|
if (_r.isError()) return _r.toStatementResult(); \
|
||||||
|
_r.unwrap(); \
|
||||||
|
})
|
||||||
|
|
||||||
|
}; // namespace Fig
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
#include <Evaluator/Value/value_forward.hpp>
|
#include <Evaluator/Value/value_forward.hpp>
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <iostream>
|
// #include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
@@ -37,6 +37,11 @@ namespace Fig
|
|||||||
return d > intMaxAsDouble || d < intMinAsDouble;
|
return d > intMaxAsDouble || d < intMinAsDouble;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool nearlyEqual(ValueType::DoubleClass l, ValueType::DoubleClass r, ValueType::DoubleClass epsilon = 1e-9)
|
||||||
|
{
|
||||||
|
return std::abs(l - r) < epsilon;
|
||||||
|
}
|
||||||
|
|
||||||
TypeInfo actualType(std::shared_ptr<const Object> obj);
|
TypeInfo actualType(std::shared_ptr<const Object> obj);
|
||||||
FString prettyType(std::shared_ptr<const Object> obj);
|
FString prettyType(std::shared_ptr<const Object> obj);
|
||||||
|
|
||||||
@@ -646,7 +651,13 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
|
|
||||||
// comparison
|
// comparison
|
||||||
friend bool operator==(const Object &lhs, const Object &rhs) { return lhs.data == rhs.data; }
|
friend bool operator==(const Object &lhs, const Object &rhs) {
|
||||||
|
if (lhs.isNumeric() && rhs.isNumeric())
|
||||||
|
{
|
||||||
|
return nearlyEqual(lhs.getNumericValue(), rhs.getNumericValue());
|
||||||
|
}
|
||||||
|
return lhs.data == rhs.data;
|
||||||
|
}
|
||||||
friend bool operator!=(const Object &lhs, const Object &rhs) { return !(lhs == rhs); }
|
friend bool operator!=(const Object &lhs, const Object &rhs) { return !(lhs == rhs); }
|
||||||
friend bool operator<(const Object &lhs, const Object &rhs)
|
friend bool operator<(const Object &lhs, const Object &rhs)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,10 +1,18 @@
|
|||||||
|
#include "Ast/Expressions/PostfixExprs.hpp"
|
||||||
|
#include <Ast/AccessModifier.hpp>
|
||||||
|
#include <Ast/Expressions/FunctionCall.hpp>
|
||||||
|
#include <Evaluator/Context/context.hpp>
|
||||||
|
#include <Evaluator/Core/ExprResult.hpp>
|
||||||
|
#include <Evaluator/Value/value.hpp>
|
||||||
|
#include <Module/builtins.hpp>
|
||||||
|
#include <Evaluator/Value/LvObject.hpp>
|
||||||
|
#include <Evaluator/Value/Type.hpp>
|
||||||
|
#include <Evaluator/Value/structInstance.hpp>
|
||||||
#include <Ast/astBase.hpp>
|
#include <Ast/astBase.hpp>
|
||||||
#include <Core/fig_string.hpp>
|
#include <Core/fig_string.hpp>
|
||||||
#include <Evaluator/Core/StatementResult.hpp>
|
#include <Evaluator/Core/StatementResult.hpp>
|
||||||
#include <Evaluator/Value/value.hpp>
|
#include <Evaluator/Value/value.hpp>
|
||||||
#include <Utils/utils.hpp>
|
#include <Error/errorLog.hpp>
|
||||||
#include <Parser/parser.hpp>
|
|
||||||
|
|
||||||
#include <Evaluator/evaluator.hpp>
|
#include <Evaluator/evaluator.hpp>
|
||||||
#include <Evaluator/evaluator_error.hpp>
|
#include <Evaluator/evaluator_error.hpp>
|
||||||
|
|
||||||
@@ -13,6 +21,9 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include <Utils/utils.hpp>
|
||||||
|
#include <Parser/parser.hpp>
|
||||||
|
|
||||||
#ifndef SourceInfo
|
#ifndef SourceInfo
|
||||||
#define SourceInfo(ptr) (ptr->sourcePath), (ptr->sourceLines)
|
#define SourceInfo(ptr) (ptr->sourcePath), (ptr->sourceLines)
|
||||||
#endif
|
#endif
|
||||||
@@ -87,15 +98,25 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
const std::vector<FString> &pathVec = i->path;
|
const std::vector<FString> &pathVec = i->path;
|
||||||
|
|
||||||
const FString &modName = pathVec.at(pathVec.size() - 1); // pathVec at least has 1 element
|
FString modName = pathVec.back(); // pathVec at least has 1 element
|
||||||
if (modName == u8"_builtins")
|
if (modName == u8"_builtins")
|
||||||
{
|
{
|
||||||
RegisterBuiltins();
|
RegisterBuiltins();
|
||||||
return StatementResult::normal();
|
return StatementResult::normal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// std::cerr << modName.toBasicString() << '\n'; DEBUG
|
||||||
|
|
||||||
|
if (ctx->containsInThisScope(modName))
|
||||||
|
{
|
||||||
|
throw EvaluatorError(
|
||||||
|
u8"RedeclarationError", std::format("{} has already been declared.", modName.toBasicString()), i);
|
||||||
|
}
|
||||||
|
|
||||||
auto path = resolveModulePath(pathVec);
|
auto path = resolveModulePath(pathVec);
|
||||||
ContextPtr modCtx = loadModule(path);
|
ContextPtr modCtx = loadModule(path);
|
||||||
|
|
||||||
|
// 冲突问题等impl存储改成 2xMap之后解决吧(咕咕咕
|
||||||
ctx->getImplRegistry().insert(modCtx->getImplRegistry().begin(), modCtx->getImplRegistry().end()); // load impl
|
ctx->getImplRegistry().insert(modCtx->getImplRegistry().begin(), modCtx->getImplRegistry().end()); // load impl
|
||||||
|
|
||||||
for (auto &[type, opRecord] : modCtx->getOpRegistry())
|
for (auto &[type, opRecord] : modCtx->getOpRegistry())
|
||||||
@@ -112,16 +133,21 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
ctx->getOpRegistry()[type] = opRecord;
|
ctx->getOpRegistry()[type] = opRecord;
|
||||||
}
|
}
|
||||||
|
if (!i->names.empty())
|
||||||
// std::cerr << modName.toBasicString() << '\n'; DEBUG
|
|
||||||
|
|
||||||
if (ctx->containsInThisScope(modName))
|
|
||||||
{
|
{
|
||||||
throw EvaluatorError(
|
for (const FString &symName : i->names)
|
||||||
u8"RedeclarationError", std::format("{} has already been declared.", modName.toBasicString()), i);
|
{
|
||||||
|
LvObject tmp(modCtx->get(symName), modCtx);
|
||||||
|
const ObjectPtr &value = tmp.get();
|
||||||
|
|
||||||
|
ctx->def(symName, tmp.declaredType(), AccessModifier::Const, value);
|
||||||
}
|
}
|
||||||
|
return StatementResult::normal();
|
||||||
|
}
|
||||||
|
if (!i->rename.empty()) { modName = i->rename; }
|
||||||
ctx->def(
|
ctx->def(
|
||||||
modName, ValueType::Module, AccessModifier::PublicConst, std::make_shared<Object>(Module(modName, modCtx)));
|
modName, ValueType::Module, AccessModifier::PublicConst, std::make_shared<Object>(Module(modName, modCtx)));
|
||||||
|
|
||||||
return StatementResult::normal();
|
return StatementResult::normal();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,28 +157,71 @@ namespace Fig
|
|||||||
StatementResult sr = StatementResult::normal();
|
StatementResult sr = StatementResult::normal();
|
||||||
for (auto &ast : asts)
|
for (auto &ast : asts)
|
||||||
{
|
{
|
||||||
Ast::Expression exp;
|
// statement, all stmt!
|
||||||
if ((exp = std::dynamic_pointer_cast<Ast::ExpressionAst>(ast))) // 保持 dynamic_pointer_cast !
|
|
||||||
{
|
|
||||||
sr = StatementResult::normal(eval(exp, global));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// statement
|
|
||||||
Ast::Statement stmt = std::static_pointer_cast<Ast::StatementAst>(ast);
|
Ast::Statement stmt = std::static_pointer_cast<Ast::StatementAst>(ast);
|
||||||
assert(stmt != nullptr);
|
assert(stmt != nullptr);
|
||||||
sr = evalStatement(stmt, global);
|
sr = evalStatement(stmt, global);
|
||||||
if (sr.isError())
|
if (sr.isError()) { handle_error(sr, stmt, global); }
|
||||||
|
if (!sr.isNormal()) { return sr; }
|
||||||
|
}
|
||||||
|
|
||||||
|
return sr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Evaluator::handle_error(const StatementResult &sr, const Ast::Statement &stmt, const ContextPtr &ctx)
|
||||||
|
{
|
||||||
|
assert(sr.isError());
|
||||||
|
const ObjectPtr &result = sr.result;
|
||||||
|
const TypeInfo &resultType = actualType(result);
|
||||||
|
|
||||||
|
if (result->is<StructInstance>() && implements(resultType, Builtins::getErrorInterfaceTypeInfo(), ctx))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
toString() -> String
|
||||||
|
getErrorClass() -> String
|
||||||
|
getErrorMessage() -> String
|
||||||
|
*/
|
||||||
|
const StructInstance &resInst = result->as<StructInstance>();
|
||||||
|
|
||||||
|
Function getErrorClassFn = ctx->getImplementedMethod(resultType, u8"getErrorClass");
|
||||||
|
getErrorClassFn = Function(getErrorClassFn.name,
|
||||||
|
getErrorClassFn.paras,
|
||||||
|
getErrorClassFn.retType,
|
||||||
|
getErrorClassFn.body,
|
||||||
|
resInst.localContext);
|
||||||
|
Function getErrorMessageFn = ctx->getImplementedMethod(resultType, u8"getErrorMessage");
|
||||||
|
getErrorMessageFn = Function(getErrorMessageFn.name,
|
||||||
|
getErrorMessageFn.paras,
|
||||||
|
getErrorMessageFn.retType,
|
||||||
|
getErrorMessageFn.body,
|
||||||
|
resInst.localContext);
|
||||||
|
|
||||||
|
const ExprResult &errorClassRes =
|
||||||
|
executeFunction(getErrorClassFn, Ast::FunctionCallArgs{}, resInst.localContext);
|
||||||
|
const ExprResult &errorMessageRes =
|
||||||
|
executeFunction(getErrorMessageFn, Ast::FunctionCallArgs{}, resInst.localContext);
|
||||||
|
|
||||||
|
if (errorClassRes.isError()) { handle_error(errorClassRes.toStatementResult(), getErrorClassFn.body, ctx); }
|
||||||
|
if (errorMessageRes.isError())
|
||||||
|
{
|
||||||
|
handle_error(errorMessageRes.toStatementResult(), getErrorMessageFn.body, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::cerr << errorClassRes.unwrap()->toString().toBasicString() << "\n";
|
||||||
|
// std::cerr << errorMessageRes.unwrap()->toString().toBasicString() << "\n";
|
||||||
|
|
||||||
|
const FString &errorClass = errorClassRes.unwrap()->as<ValueType::StringClass>();
|
||||||
|
const FString &errorMessage = errorMessageRes.unwrap()->as<ValueType::StringClass>();
|
||||||
|
|
||||||
|
ErrorLog::logFigErrorInterface(errorClass, errorMessage);
|
||||||
|
std::exit(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
throw EvaluatorError(u8"UncaughtExceptionError",
|
throw EvaluatorError(u8"UncaughtExceptionError",
|
||||||
std::format("Uncaught exception: {}", sr.result->toString().toBasicString()),
|
std::format("Uncaught exception: {}", sr.result->toString().toBasicString()),
|
||||||
stmt);
|
stmt);
|
||||||
}
|
}
|
||||||
if (!sr.isNormal()) { return sr; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Evaluator::printStackTrace()
|
void Evaluator::printStackTrace()
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "Ast/AccessModifier.hpp"
|
||||||
|
#include "Ast/Expressions/BinaryExpr.hpp"
|
||||||
|
#include "Ast/Expressions/ValueExpr.hpp"
|
||||||
|
#include "Ast/Expressions/VarExpr.hpp"
|
||||||
|
#include "Ast/Statements/ControlSt.hpp"
|
||||||
|
#include "Ast/astBase.hpp"
|
||||||
|
#include "Ast/functionParameters.hpp"
|
||||||
|
#include "Value/value.hpp"
|
||||||
#include <Ast/Expressions/FunctionCall.hpp>
|
#include <Ast/Expressions/FunctionCall.hpp>
|
||||||
#include <Ast/Expressions/InitExpr.hpp>
|
#include <Ast/Expressions/InitExpr.hpp>
|
||||||
#include <Ast/Statements/ImplementSt.hpp>
|
#include <Ast/Statements/ImplementSt.hpp>
|
||||||
@@ -10,9 +18,13 @@
|
|||||||
#include <Error/error.hpp>
|
#include <Error/error.hpp>
|
||||||
#include <Module/builtins.hpp>
|
#include <Module/builtins.hpp>
|
||||||
#include <Evaluator/Value/LvObject.hpp>
|
#include <Evaluator/Value/LvObject.hpp>
|
||||||
|
#include <cstddef>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
#include <Evaluator/Core/StatementResult.hpp>
|
#include <Evaluator/Core/StatementResult.hpp>
|
||||||
|
#include <Evaluator/Core/ExprResult.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <source_location>
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
@@ -47,6 +59,43 @@ namespace Fig
|
|||||||
Function f(name, fn, argc);
|
Function f(name, fn, argc);
|
||||||
global->def(name, ValueType::Function, AccessModifier::Const, std::make_shared<Object>(f));
|
global->def(name, ValueType::Function, AccessModifier::Const, std::make_shared<Object>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
global->setImplRecord(
|
||||||
|
Builtins::getTypeErrorStructTypeInfo(),
|
||||||
|
Builtins::getErrorInterfaceTypeInfo(),
|
||||||
|
ImplRecord{
|
||||||
|
.interfaceType = Builtins::getErrorInterfaceTypeInfo(),
|
||||||
|
.structType = Builtins::getTypeErrorStructTypeInfo(),
|
||||||
|
.implMethods = {
|
||||||
|
{u8"toString",
|
||||||
|
Function(
|
||||||
|
u8"toString",
|
||||||
|
Ast::FunctionParameters{},
|
||||||
|
ValueType::String,
|
||||||
|
std::make_shared<Ast::BlockStatementAst>(std::vector<Ast::Statement>(
|
||||||
|
{std::make_shared<Ast::ReturnSt>(std::make_shared<Ast::BinaryExprAst>(
|
||||||
|
std::make_shared<Ast::ValueExprAst>(std::make_shared<Object>(u8"TypeError: ")),
|
||||||
|
Ast::Operator::Add,
|
||||||
|
std::make_shared<Ast::FunctionCallExpr>(
|
||||||
|
std::make_shared<Ast::VarExprAst>(u8"getErrorMessage"),
|
||||||
|
Ast::FunctionArguments{})))})),
|
||||||
|
nullptr)},
|
||||||
|
{u8"getErrorClass",
|
||||||
|
Function(u8"getErrorClass",
|
||||||
|
Ast::FunctionParameters{},
|
||||||
|
ValueType::String,
|
||||||
|
std::make_shared<Ast::BlockStatementAst>(std::vector<Ast::Statement>(
|
||||||
|
{std::make_shared<Ast::ReturnSt>(std::make_shared<Ast::ValueExprAst>(
|
||||||
|
std::make_shared<Object>(FString(u8"TypeError"))))})),
|
||||||
|
nullptr)},
|
||||||
|
{u8"getErrorMessage",
|
||||||
|
Function(u8"getErrorMessage",
|
||||||
|
Ast::FunctionParameters{},
|
||||||
|
ValueType::String,
|
||||||
|
std::make_shared<Ast::BlockStatementAst>(std::vector<Ast::Statement>(
|
||||||
|
{std::make_shared<Ast::ReturnSt>(std::make_shared<Ast::VarExprAst>(u8"msg"))})),
|
||||||
|
nullptr)},
|
||||||
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterBuiltinsValue()
|
void RegisterBuiltinsValue()
|
||||||
@@ -61,25 +110,35 @@ namespace Fig
|
|||||||
|
|
||||||
bool isInterfaceSignatureMatch(const Ast::ImplementMethod &, const Ast::InterfaceMethod &);
|
bool isInterfaceSignatureMatch(const Ast::ImplementMethod &, const Ast::InterfaceMethod &);
|
||||||
|
|
||||||
/* Left-value eval*/
|
ObjectPtr genTypeError(const FString &_msg,
|
||||||
LvObject evalVarExpr(Ast::VarExpr, ContextPtr);
|
const Ast::AstBase &_ast,
|
||||||
LvObject evalMemberExpr(Ast::MemberExpr, ContextPtr); // a.b
|
ContextPtr ctx,
|
||||||
LvObject evalIndexExpr(Ast::IndexExpr, ContextPtr); // a[b]
|
std::source_location loc = std::source_location::current())
|
||||||
|
{
|
||||||
|
ContextPtr stCtx = std::make_shared<Context>(u8"<TypeError Instance>");
|
||||||
|
stCtx->def(u8"msg", ValueType::String, AccessModifier::Const, std::make_shared<Object>(_msg));
|
||||||
|
return std::make_shared<Object>(StructInstance(Builtins::getTypeErrorStructTypeInfo(), stCtx));
|
||||||
|
}
|
||||||
|
|
||||||
LvObject evalLv(Ast::Expression, ContextPtr); // for access: a.b / index a[b]
|
/* Left-value eval*/
|
||||||
|
ExprResult evalVarExpr(Ast::VarExpr, ContextPtr); // identifier: a, b, c
|
||||||
|
ExprResult evalMemberExpr(Ast::MemberExpr, ContextPtr); // a.b
|
||||||
|
ExprResult evalIndexExpr(Ast::IndexExpr, ContextPtr); // a[b]
|
||||||
|
|
||||||
|
ExprResult evalLv(Ast::Expression, ContextPtr); // for access: a.b / index a[b]
|
||||||
|
|
||||||
/* Right-value eval*/
|
/* Right-value eval*/
|
||||||
RvObject evalInitExpr(Ast::InitExpr, ContextPtr); // only allows evalUnary to call
|
ExprResult evalInitExpr(Ast::InitExpr, ContextPtr);
|
||||||
RvObject evalBinary(Ast::BinaryExpr, ContextPtr); // normal binary expr: +, -, *....
|
ExprResult evalBinary(Ast::BinaryExpr, ContextPtr); // normal binary expr: +, -, *....
|
||||||
RvObject evalUnary(Ast::UnaryExpr, ContextPtr); // unary expr
|
ExprResult evalUnary(Ast::UnaryExpr, ContextPtr); // unary expr
|
||||||
RvObject evalTernary(Ast::TernaryExpr, ContextPtr); // ternary expr
|
ExprResult evalTernary(Ast::TernaryExpr, ContextPtr); // ternary expr
|
||||||
|
|
||||||
RvObject executeFunction(const Function &fn, const Ast::FunctionCallArgs &, ContextPtr); // fn, fn context
|
ExprResult executeFunction(const Function &fn, const Ast::FunctionCallArgs &, ContextPtr); // fn, fn context
|
||||||
|
|
||||||
RvObject evalFunctionCall(const Ast::FunctionCall &,
|
ExprResult evalFunctionCall(const Ast::FunctionCall &,
|
||||||
ContextPtr); // function call
|
ContextPtr); // function call
|
||||||
|
|
||||||
RvObject eval(Ast::Expression, ContextPtr);
|
ExprResult eval(Ast::Expression, ContextPtr);
|
||||||
|
|
||||||
StatementResult evalBlockStatement(Ast::BlockStatement, ContextPtr); // block
|
StatementResult evalBlockStatement(Ast::BlockStatement, ContextPtr); // block
|
||||||
StatementResult evalStatement(Ast::Statement, ContextPtr); // statement
|
StatementResult evalStatement(Ast::Statement, ContextPtr); // statement
|
||||||
@@ -91,6 +150,8 @@ namespace Fig
|
|||||||
|
|
||||||
StatementResult Run(std::vector<Ast::AstBase>); // Entry
|
StatementResult Run(std::vector<Ast::AstBase>); // Entry
|
||||||
|
|
||||||
|
void handle_error(const StatementResult &, const Ast::Statement &, const ContextPtr &);
|
||||||
|
|
||||||
void printStackTrace();
|
void printStackTrace();
|
||||||
};
|
};
|
||||||
}; // namespace Fig
|
}; // namespace Fig
|
||||||
@@ -97,6 +97,7 @@ namespace Fig
|
|||||||
{FString(u8"catch"), TokenType::Catch},
|
{FString(u8"catch"), TokenType::Catch},
|
||||||
{FString(u8"throw"), TokenType::Throw},
|
{FString(u8"throw"), TokenType::Throw},
|
||||||
{FString(u8"Finally"), TokenType::Finally},
|
{FString(u8"Finally"), TokenType::Finally},
|
||||||
|
{FString(u8"as"), TokenType::As},
|
||||||
|
|
||||||
// {FString(u8"Null"), TokenType::TypeNull},
|
// {FString(u8"Null"), TokenType::TypeNull},
|
||||||
// {FString(u8"Int"), TokenType::TypeInt},
|
// {FString(u8"Int"), TokenType::TypeInt},
|
||||||
|
|||||||
@@ -31,6 +31,27 @@ public interface Error
|
|||||||
getErrorMessage() -> String;
|
getErrorMessage() -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct TypeError
|
||||||
|
{
|
||||||
|
public msg: String;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for TypeError
|
||||||
|
{
|
||||||
|
toString()
|
||||||
|
{
|
||||||
|
return "TypeError: " + getErrorMessage();
|
||||||
|
}
|
||||||
|
getErrorClass()
|
||||||
|
{
|
||||||
|
return "TypeError";
|
||||||
|
}
|
||||||
|
getErrorMessage()
|
||||||
|
{
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Operation interface
|
// Operation interface
|
||||||
|
|
||||||
public interface Operation
|
public interface Operation
|
||||||
|
|||||||
@@ -3,7 +3,12 @@
|
|||||||
Library/std/std.fig
|
Library/std/std.fig
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import io; // link std.io
|
import io as std_io;
|
||||||
import value; // link std.type
|
import value as std_value;
|
||||||
import math; // link std.math
|
import math as std_math;
|
||||||
import tester; // link std.tester
|
import test as std_test;
|
||||||
|
|
||||||
|
public const io := std_io; // link std.io
|
||||||
|
public const value := std_value; // link std.type
|
||||||
|
public const math := std_math; // link std.math
|
||||||
|
public const test := std_test; // link std.test
|
||||||
@@ -1,13 +1,42 @@
|
|||||||
|
#include "Ast/Expressions/BinaryExpr.hpp"
|
||||||
|
#include "Ast/Expressions/FunctionCall.hpp"
|
||||||
|
#include "Ast/Expressions/ValueExpr.hpp"
|
||||||
|
#include "Ast/Expressions/VarExpr.hpp"
|
||||||
|
#include "Ast/Statements/ControlSt.hpp"
|
||||||
|
#include "Ast/astBase.hpp"
|
||||||
|
#include "Ast/functionParameters.hpp"
|
||||||
|
#include <Evaluator/Context/context.hpp>
|
||||||
|
#include <Core/fig_string.hpp>
|
||||||
|
#include <Ast/AccessModifier.hpp>
|
||||||
|
#include <Evaluator/Value/structType.hpp>
|
||||||
|
#include <Evaluator/Value/value.hpp>
|
||||||
#include <Module/builtins.hpp>
|
#include <Module/builtins.hpp>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <print>
|
#include <print>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace Fig::Builtins
|
namespace Fig::Builtins
|
||||||
{
|
{
|
||||||
|
const TypeInfo &getErrorInterfaceTypeInfo()
|
||||||
|
{
|
||||||
|
static const TypeInfo ErrorInterfaceTypeInfo(u8"Error", true);
|
||||||
|
return ErrorInterfaceTypeInfo;
|
||||||
|
}
|
||||||
|
const TypeInfo &getTypeErrorStructTypeInfo()
|
||||||
|
{
|
||||||
|
static const TypeInfo TypeErrorStructTypeInfo(u8"TypeError", true);
|
||||||
|
return TypeErrorStructTypeInfo;
|
||||||
|
}
|
||||||
|
const TypeInfo &getOperationInterfaceTypeInfo()
|
||||||
|
{
|
||||||
|
static const TypeInfo OperationInterfaceTypeInfo(u8"Operation", true);
|
||||||
|
return OperationInterfaceTypeInfo;
|
||||||
|
}
|
||||||
const std::unordered_map<FString, ObjectPtr> &getBuiltinValues()
|
const std::unordered_map<FString, ObjectPtr> &getBuiltinValues()
|
||||||
{
|
{
|
||||||
static const std::unordered_map<FString, ObjectPtr> builtinValues = {
|
static const std::unordered_map<FString, ObjectPtr> builtinValues = {
|
||||||
@@ -28,6 +57,11 @@ namespace Fig::Builtins
|
|||||||
Ast::FunctionParameters({}, {}),
|
Ast::FunctionParameters({}, {}),
|
||||||
std::make_shared<Ast::VarExprAst>(u8"String"),
|
std::make_shared<Ast::VarExprAst>(u8"String"),
|
||||||
nullptr)}))},
|
nullptr)}))},
|
||||||
|
{u8"TypeError", std::make_shared<Object>(StructType(
|
||||||
|
getTypeErrorStructTypeInfo(),
|
||||||
|
std::make_shared<Context>(u8"<Built-in `TypeError`>"),
|
||||||
|
{Field(AccessModifier::Public, u8"msg", ValueType::String, nullptr)}
|
||||||
|
))},
|
||||||
{u8"Operation", std::make_shared<Object>(InterfaceType(getOperationInterfaceTypeInfo(), {}))},
|
{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))},
|
||||||
@@ -380,4 +414,4 @@ namespace Fig::Builtins
|
|||||||
};
|
};
|
||||||
return builtinFunctions;
|
return builtinFunctions;
|
||||||
}
|
}
|
||||||
}
|
} // namespace Fig::Builtins
|
||||||
@@ -26,12 +26,9 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline static const TypeInfo &getErrorInterfaceTypeInfo()
|
const TypeInfo &getErrorInterfaceTypeInfo();
|
||||||
{
|
|
||||||
static const TypeInfo ErrorInterfaceTypeInfo(u8"Error", true);
|
|
||||||
return ErrorInterfaceTypeInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const TypeInfo &getTypeErrorStructTypeInfo();
|
||||||
/*
|
/*
|
||||||
interface Operation
|
interface Operation
|
||||||
{
|
{
|
||||||
@@ -40,11 +37,7 @@ namespace Fig
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline static const TypeInfo &getOperationInterfaceTypeInfo()
|
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();
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,9 @@ namespace Fig
|
|||||||
{Ast::Operator::GreaterEqual, {100, 101}},
|
{Ast::Operator::GreaterEqual, {100, 101}},
|
||||||
{Ast::Operator::Is, {100, 101}},
|
{Ast::Operator::Is, {100, 101}},
|
||||||
|
|
||||||
|
// 转换
|
||||||
|
{Ast::Operator::As, {105, 106}},
|
||||||
|
|
||||||
// 位移
|
// 位移
|
||||||
{Ast::Operator::ShiftLeft, {110, 111}},
|
{Ast::Operator::ShiftLeft, {110, 111}},
|
||||||
{Ast::Operator::ShiftRight, {110, 111}},
|
{Ast::Operator::ShiftRight, {110, 111}},
|
||||||
@@ -998,6 +1001,8 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
next(); // consume `import`
|
next(); // consume `import`
|
||||||
std::vector<FString> path;
|
std::vector<FString> path;
|
||||||
|
std::vector<FString> names;
|
||||||
|
FString rename;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
expect(TokenType::Identifier, u8"package name");
|
expect(TokenType::Identifier, u8"package name");
|
||||||
@@ -1008,13 +1013,41 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
next(); // consume `.`
|
next(); // consume `.`
|
||||||
}
|
}
|
||||||
|
else if (isThis(TokenType::As)) { break; }
|
||||||
|
else if (isThis(TokenType::LeftBrace)) { break; }
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw SyntaxError();
|
throwAddressableError<SyntaxError>(u8"invalid syntax");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isThis(TokenType::As))
|
||||||
|
{
|
||||||
|
next(); // consume `as`
|
||||||
|
expect(TokenType::Identifier, u8"new name");
|
||||||
|
rename = currentToken().getValue();
|
||||||
|
next(); // consume name
|
||||||
|
}
|
||||||
|
else if (isThis(TokenType::LeftBrace))
|
||||||
|
{
|
||||||
|
next(); // consume `{`
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (isThis(TokenType::RightBrace))
|
||||||
|
{
|
||||||
|
next(); // consume `}`
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (isThis(TokenType::Comma))
|
||||||
|
{
|
||||||
|
next(); // consume `,`
|
||||||
|
}
|
||||||
|
expect(TokenType::Identifier, u8"symbol name");
|
||||||
|
names.push_back(currentToken().getValue());
|
||||||
|
next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expectSemicolon();
|
expectSemicolon();
|
||||||
return makeAst<Ast::ImportSt>(path);
|
return makeAst<Ast::ImportSt>(path, names, rename);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ast::Expression Parser::parseExpression(Precedence bp, TokenType stop, TokenType stop2, TokenType stop3)
|
Ast::Expression Parser::parseExpression(Precedence bp, TokenType stop, TokenType stop2, TokenType stop3)
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ namespace Fig
|
|||||||
Catch, // catch
|
Catch, // catch
|
||||||
Throw, // throw
|
Throw, // throw
|
||||||
Finally, // finally
|
Finally, // finally
|
||||||
|
As, // as
|
||||||
|
|
||||||
// TypeNull, // Null
|
// TypeNull, // Null
|
||||||
// TypeInt, // Int
|
// TypeInt, // Int
|
||||||
|
|||||||
Reference in New Issue
Block a user