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