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

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

View File

@@ -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"

View File

@@ -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",

View File

@@ -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;
} }

View File

@@ -35,7 +35,7 @@ namespace Fig::Ast
TupleExpr, // (1, 2, 3) TupleExpr, // (1, 2, 3)
MapExpr, // {a: 1} MapExpr, // {a: 1}
InitExpr, // struct{"123", 456} InitExpr, // struct{"123", 456}
FunctionLiteralExpr, FunctionLiteralExpr,
/* Statement */ /* Statement */
@@ -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},

View File

@@ -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'; }

View File

@@ -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;

View File

@@ -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();
@@ -16,8 +17,8 @@ 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));
} }

View File

@@ -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)),

View File

@@ -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))
{ {

View File

@@ -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",
@@ -150,11 +151,12 @@ namespace Fig
std::vector<std::pair<FString, ObjectPtr>> evaluatedArgs; 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) 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))

View File

@@ -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;

View File

@@ -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 &paras = implMethod.paras; const Ast::FunctionParameters &paras = implMethod.paras;
for (size_t i = 0; i < paraCnt; ++i) for (size_t i = 0; i < paraCnt; ++i)
{ {
const TypeInfo &paraType = actualType(eval(paras.posParas[i].second, ctx)); const TypeInfo &paraType =
actualType(check_unwrap_stres(eval(paras.posParas[i].second, ctx)));
if (paraType != ValueType::Any && paraType != structType) 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: {

View File

@@ -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(

View File

@@ -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>())
{ {
// 运算符重载 // 运算符重载

View File

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

View File

@@ -0,0 +1,72 @@
#pragma once
#include <Core/fig_string.hpp>
#include <Evaluator/Value/value_forward.hpp>
#include <Evaluator/Value/LvObject.hpp>
#include <variant>
#include <cassert>
namespace Fig
{
struct StatementResult;
struct ExprResult
{
std::variant<LvObject, RvObject> result;
enum class Flow
{
Normal,
Error,
} flow;
ExprResult(ObjectPtr _result, Flow _flow = Flow::Normal) : result(_result), flow(_flow) {}
ExprResult(const LvObject &_result, Flow _flow = Flow::Normal) : result(_result), flow(_flow) {}
static ExprResult normal(ObjectPtr _result) { return ExprResult(_result); }
static ExprResult normal(const LvObject &_result) { return ExprResult(_result); }
static ExprResult error(ObjectPtr _result) { return ExprResult(_result, Flow::Error); }
static ExprResult error(const LvObject &_result) { return ExprResult(_result, Flow::Error); }
bool isNormal() const { return flow == Flow::Normal; }
bool isError() const { return flow == Flow::Error; }
bool isResultLv() const { return std::holds_alternative<LvObject>(result); }
ObjectPtr &unwrap()
{
if (!isNormal()) { assert(false && "unwrap abnormal ExprResult!"); }
return std::get<RvObject>(result);
}
const ObjectPtr &unwrap() const
{
if (!isNormal()) { assert(false && "unwrap abnormal ExprResult!"); }
return std::get<RvObject>(result);
}
const LvObject &unwrap_lv() const { return std::get<LvObject>(result); }
StatementResult toStatementResult() const;
};
#define check_unwrap(expr) \
({ \
auto _r = (expr); \
if (_r.isError()) return _r; \
_r.unwrap(); \
})
#define check_unwrap_lv(expr) \
({ \
auto _r = (expr); \
if (_r.isError()) return _r; \
_r.unwrap_lv(); \
})
#define check_unwrap_stres(expr) \
({ \
auto _r = (expr); \
if (_r.isError()) return _r.toStatementResult(); \
_r.unwrap(); \
})
}; // namespace Fig

View File

@@ -10,7 +10,7 @@
#include <Evaluator/Value/value_forward.hpp> #include <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)
{ {

View File

@@ -1,10 +1,18 @@
#include "Ast/Expressions/PostfixExprs.hpp"
#include <Ast/AccessModifier.hpp>
#include <Ast/Expressions/FunctionCall.hpp>
#include <Evaluator/Context/context.hpp>
#include <Evaluator/Core/ExprResult.hpp>
#include <Evaluator/Value/value.hpp>
#include <Module/builtins.hpp>
#include <Evaluator/Value/LvObject.hpp>
#include <Evaluator/Value/Type.hpp>
#include <Evaluator/Value/structInstance.hpp>
#include <Ast/astBase.hpp> #include <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
@@ -50,7 +61,7 @@ namespace Fig
std::vector<FString> modSourceLines; std::vector<FString> modSourceLines;
if (mod_ast_cache.contains(modSourcePath)) if (mod_ast_cache.contains(modSourcePath))
{ {
auto &[_sl, _asts] = mod_ast_cache[modSourcePath]; auto &[_sl, _asts] = mod_ast_cache[modSourcePath];
modSourceLines = _sl; modSourceLines = _sl;
@@ -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,30 +157,73 @@ 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 ! Ast::Statement stmt = std::static_pointer_cast<Ast::StatementAst>(ast);
{ assert(stmt != nullptr);
sr = StatementResult::normal(eval(exp, global)); sr = evalStatement(stmt, global);
} if (sr.isError()) { handle_error(sr, stmt, global); }
else if (!sr.isNormal()) { return sr; }
{
// 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; }
}
} }
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() void Evaluator::printStackTrace()
{ {
if (global) global->printStackTrace(); if (global) global->printStackTrace();

View File

@@ -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

View File

@@ -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},

View File

@@ -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

View File

@@ -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

View File

@@ -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,7 +57,12 @@ namespace Fig::Builtins
Ast::FunctionParameters({}, {}), Ast::FunctionParameters({}, {}),
std::make_shared<Ast::VarExprAst>(u8"String"), std::make_shared<Ast::VarExprAst>(u8"String"),
nullptr)}))}, nullptr)}))},
{u8"Operation", std::make_shared<Object>(InterfaceType(getOperationInterfaceTypeInfo(), {}))}, {u8"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"Any", std::make_shared<Object>(StructType(ValueType::Any, nullptr, {}, true))},
{u8"Int", std::make_shared<Object>(StructType(ValueType::Int, nullptr, {}, true))}, {u8"Int", std::make_shared<Object>(StructType(ValueType::Int, nullptr, {}, true))},
@@ -119,8 +153,8 @@ namespace Fig::Builtins
}}, }},
{u8"__fvalue_type", {u8"__fvalue_type",
[](const std::vector<ObjectPtr> &args) -> ObjectPtr { [](const std::vector<ObjectPtr> &args) -> ObjectPtr {
return std::make_shared<Object>(args[0]->getTypeInfo().toString()); return std::make_shared<Object>(args[0]->getTypeInfo().toString());
}}, }},
{u8"__fvalue_int_parse", {u8"__fvalue_int_parse",
[](const std::vector<ObjectPtr> &args) -> ObjectPtr { [](const std::vector<ObjectPtr> &args) -> ObjectPtr {
FString str = args[0]->as<ValueType::StringClass>(); FString str = args[0]->as<ValueType::StringClass>();
@@ -380,4 +414,4 @@ namespace Fig::Builtins
}; };
return builtinFunctions; return builtinFunctions;
} }
} } // namespace Fig::Builtins

View File

@@ -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();

View File

@@ -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)

View File

@@ -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