回档之后的重写。部分问题修复。添加了什么我也忘了

This commit is contained in:
2026-02-01 15:52:28 +08:00
parent 61bffdc743
commit aea716ced2
50 changed files with 3676 additions and 2997 deletions

View File

@@ -0,0 +1,510 @@
#include <Evaluator/Value/LvObject.hpp>
#include <Evaluator/evaluator.hpp>
#include <Evaluator/evaluator_error.hpp>
#include <Utils/utils.hpp>
namespace Fig
{
StatementResult Evaluator::evalStatement(Ast::Statement stmt, ContextPtr ctx)
{
using enum Ast::AstType;
switch (stmt->getType())
{
case ImportSt: {
auto i = std::static_pointer_cast<Ast::ImportSt>(stmt);
return evalImportSt(i, ctx);
}
case VarDefSt: {
auto varDef = std::static_pointer_cast<Ast::VarDefAst>(stmt);
if (ctx->containsInThisScope(varDef->name))
{
throw EvaluatorError(
u8"RedeclarationError",
std::format("Variable `{}` already declared in this scope", varDef->name.toBasicString()),
varDef);
}
RvObject value = nullptr;
if (varDef->expr) { value = eval(varDef->expr, ctx); }
TypeInfo declaredType; // default is Any
const Ast::Expression &declaredTypeExp = varDef->declaredType;
if (varDef->followupType) { declaredType = actualType(value); }
else if (declaredTypeExp)
{
ObjectPtr declaredTypeValue = eval(declaredTypeExp, ctx);
declaredType = actualType(declaredTypeValue);
if (value != nullptr && !isTypeMatch(declaredType, value, ctx))
{
throw EvaluatorError(u8"TypeError",
std::format("Variable `{}` expects init-value type `{}`, but got '{}'",
varDef->name.toBasicString(),
prettyType(declaredTypeValue).toBasicString(),
prettyType(value).toBasicString()),
varDef->expr);
}
else if (value == nullptr)
{
value = std::make_shared<Object>(Object::defaultValue(declaredType));
} // else -> Ok
} // else -> type is Any (default)
AccessModifier am =
(varDef->isConst ? (varDef->isPublic ? AccessModifier::PublicConst : AccessModifier::Const) :
(varDef->isPublic ? AccessModifier::Public : AccessModifier::Normal));
ctx->def(varDef->name, declaredType, am, value);
return StatementResult::normal();
}
case FunctionDefSt: {
auto fnDef = std::static_pointer_cast<Ast::FunctionDefSt>(stmt);
const FString &fnName = fnDef->name;
if (ctx->containsInThisScope(fnName))
{
throw EvaluatorError(
u8"RedeclarationError",
std::format("Function `{}` already declared in this scope", fnName.toBasicString()),
fnDef);
}
TypeInfo returnType = ValueType::Any;
if (fnDef->retType)
{
ObjectPtr returnTypeValue = eval(fnDef->retType, ctx);
returnType = actualType(returnTypeValue);
}
Function fn(fnDef->paras, returnType, fnDef->body, ctx);
ctx->def(fnName,
ValueType::Function,
(fnDef->isPublic ? AccessModifier::PublicConst : AccessModifier::Const),
std::make_shared<Object>(fn));
return StatementResult::normal();
}
case StructSt: {
auto stDef = std::static_pointer_cast<Ast::StructDefSt>(stmt);
if (ctx->containsInThisScope(stDef->name))
{
throw EvaluatorError(
u8"RedeclarationError",
std::format("Structure '{}' already defined in this scope", stDef->name.toBasicString()),
stDef);
}
std::vector<Field> fields;
std::vector<FString> _fieldNames;
for (Ast::StructDefField field : stDef->fields)
{
if (Utils::vectorContains(field.fieldName, _fieldNames))
{
throw EvaluatorError(u8"RedeclarationError",
std::format("Field '{}' already defined in structure '{}'",
field.fieldName.toBasicString(),
stDef->name.toBasicString()),
stDef);
}
TypeInfo fieldType = ValueType::Any;
if (field.declaredType)
{
ObjectPtr declaredTypeValue = eval(field.declaredType, ctx);
fieldType = actualType(declaredTypeValue);
}
fields.push_back(Field(field.am, field.fieldName, fieldType, field.defaultValueExpr));
}
ContextPtr defContext = std::make_shared<Context>(FString(std::format("<Struct {} at {}:{}>",
stDef->name.toBasicString(),
stDef->getAAI().line,
stDef->getAAI().column)),
ctx);
const Ast::BlockStatement &body = stDef->body;
for (auto &st : body->stmts)
{
if (st->getType() != Ast::AstType::FunctionDefSt)
{
throw EvaluatorError(u8"UnexpectedStatementInStructError",
std::format("Unexpected statement `{}` in struct declaration",
st->toString().toBasicString()),
st);
}
evalStatement(st, defContext); // function def st
}
AccessModifier am = (stDef->isPublic ? AccessModifier::PublicConst : AccessModifier::Const);
TypeInfo type(stDef->name, true); // register type name
ctx->def(stDef->name,
ValueType::StructType,
am,
std::make_shared<Object>(StructType(type, defContext, fields)));
return StatementResult::normal();
}
case InterfaceDefSt: {
auto ifd = std::static_pointer_cast<Ast::InterfaceDefAst>(stmt);
const FString &interfaceName = ifd->name;
if (ctx->containsInThisScope(interfaceName))
{
throw EvaluatorError(
u8"RedeclarationError",
std::format("Interface `{}` already declared in this scope", interfaceName.toBasicString()),
ifd);
}
TypeInfo type(interfaceName, true); // register interface
ctx->def(interfaceName,
type,
(ifd->isPublic ? AccessModifier::PublicConst : AccessModifier::Const),
std::make_shared<Object>(InterfaceType(type, ifd->methods)));
return StatementResult::normal();
}
case ImplementSt: {
auto ip = std::static_pointer_cast<Ast::ImplementAst>(stmt);
TypeInfo structType(ip->structName);
TypeInfo interfaceType(ip->interfaceName);
if (ctx->hasImplRegisted(structType, interfaceType))
{
throw EvaluatorError(u8"DuplicateImplError",
std::format("Duplicate implement `{}` for `{}`",
interfaceType.toString().toBasicString(),
structType.toString().toBasicString()),
ip);
}
if (!ctx->contains(ip->interfaceName))
{
throw EvaluatorError(u8"InterfaceNotFoundError",
std::format("Interface '{}' not found", ip->interfaceName.toBasicString()),
ip);
}
if (!ctx->contains(ip->structName))
{
throw EvaluatorError(u8"StructNotFoundError",
std::format("Struct '{}' not found", ip->structName.toBasicString()),
ip);
}
auto interfaceSlot = ctx->get(ip->interfaceName);
auto structSlot = ctx->get(ip->structName);
LvObject interfaceLv(interfaceSlot, ctx);
LvObject structLv(structSlot, ctx);
ObjectPtr interfaceObj = interfaceLv.get();
ObjectPtr structTypeObj = structLv.get();
if (!interfaceObj->is<InterfaceType>())
{
throw EvaluatorError(
u8"NotAInterfaceError",
std::format("Variable `{}` is not a interface", ip->interfaceName.toBasicString()),
ip);
}
if (!structTypeObj->is<StructType>())
{
throw EvaluatorError(
u8"NotAStructType",
std::format("Variable `{}` is not a struct type", ip->structName.toBasicString()),
ip);
}
auto &implementMethods = ip->methods;
InterfaceType &interface = interfaceObj->as<InterfaceType>();
// ===== interface implementation validation =====
ImplRecord record{interfaceType, structType, {}};
std::unordered_map<FString, Ast::InterfaceMethod> ifaceMethods;
for (auto &m : interface.methods)
{
if (ifaceMethods.contains(m.name))
{
throw EvaluatorError(u8"InterfaceDuplicateMethodError",
std::format("Interface '{}' has duplicate method '{}'",
interfaceType.toString().toBasicString(),
m.name.toBasicString()),
ip);
}
ifaceMethods[m.name] = m;
}
std::unordered_set<FString> implemented;
for (auto &implMethod : implementMethods)
{
const FString &name = implMethod.name;
// ---- redundant impl ----
if (!ifaceMethods.contains(name))
{
throw EvaluatorError(u8"RedundantImplementationError",
std::format("Struct '{}' implements extra method '{}' "
"which is not required by interface '{}'",
structType.toString().toBasicString(),
name.toBasicString(),
interfaceType.toString().toBasicString()),
ip);
}
if (implemented.contains(name))
{
throw EvaluatorError(u8"DuplicateImplementMethodError",
std::format("Duplicate implement method '{}'", name.toBasicString()),
ip);
}
auto &ifMethod = ifaceMethods[name];
// ---- signature check ----
if (!isInterfaceSignatureMatch(implMethod, ifMethod))
{
throw EvaluatorError(u8"InterfaceSignatureMismatch",
std::format("Interface method '{}({})' signature mismatch with "
"implementation '{}({})'",
ifMethod.name.toBasicString(),
ifMethod.paras.toString().toBasicString(),
implMethod.name.toBasicString(),
implMethod.paras.toString().toBasicString()),
ip);
}
if (ctx->hasMethodImplemented(structType, name))
{
throw EvaluatorError(u8"DuplicateImplementMethodError",
std::format("Method '{}' already implemented by another interface "
"for struct '{}'",
name.toBasicString(),
structType.toString().toBasicString()),
ip);
}
implemented.insert(name);
ObjectPtr returnTypeValue = eval(ifMethod.returnType, ctx);
record.implMethods[name] =
Function(implMethod.paras, actualType(returnTypeValue), implMethod.body, ctx);
}
for (auto &m : interface.methods)
{
if (implemented.contains(m.name)) continue;
if (m.hasDefaultBody()) continue;
throw EvaluatorError(u8"MissingImplementationError",
std::format("Struct '{}' does not implement required interface method '{}' "
"and interface '{}' provides no default implementation",
structType.toString().toBasicString(),
m.name.toBasicString(),
interfaceType.toString().toBasicString()),
ip);
}
ctx->setImplRecord(structType, interfaceType, record);
return StatementResult::normal();
}
case IfSt: {
auto ifSt = std::static_pointer_cast<Ast::IfSt>(stmt);
ObjectPtr condVal = eval(ifSt->condition, ctx);
if (condVal->getTypeInfo() != ValueType::Bool)
{
throw EvaluatorError(
u8"TypeError",
std::format("Condition must be boolean, but got '{}'", prettyType(condVal).toBasicString()),
ifSt->condition);
}
if (condVal->as<ValueType::BoolClass>()) { return evalBlockStatement(ifSt->body, ctx); }
// else
for (const auto &elif : ifSt->elifs)
{
ObjectPtr elifCondVal = eval(elif->condition, ctx);
if (elifCondVal->getTypeInfo() != ValueType::Bool)
{
throw EvaluatorError(
u8"TypeError",
std::format("Condition must be boolean, but got '{}'", prettyType(condVal).toBasicString()),
ifSt->condition);
}
if (elifCondVal->as<ValueType::BoolClass>()) { return evalBlockStatement(elif->body, ctx); }
}
if (ifSt->els) { return evalBlockStatement(ifSt->els->body, ctx); }
return StatementResult::normal();
};
case WhileSt: {
auto whileSt = std::static_pointer_cast<Ast::WhileSt>(stmt);
while (true)
{
ObjectPtr condVal = eval(whileSt->condition, ctx);
if (condVal->getTypeInfo() != ValueType::Bool)
{
throw EvaluatorError(
u8"TypeError",
std::format("Condition must be boolean, but got '{}'", prettyType(condVal).toBasicString()),
whileSt->condition);
}
if (!condVal->as<ValueType::BoolClass>()) { break; }
ContextPtr loopContext = std::make_shared<Context>(
FString(std::format("<While {}:{}>", whileSt->getAAI().line, whileSt->getAAI().column)),
ctx); // every loop has its own context
StatementResult sr = evalBlockStatement(whileSt->body, loopContext);
if (sr.shouldReturn()) { return sr; }
if (sr.shouldBreak()) { break; }
if (sr.shouldContinue()) { continue; }
}
return StatementResult::normal();
};
case ForSt: {
auto forSt = std::static_pointer_cast<Ast::ForSt>(stmt);
ContextPtr loopContext = std::make_shared<Context>(
FString(std::format("<For {}:{}>", forSt->getAAI().line, forSt->getAAI().column)),
ctx); // for loop has its own context
evalStatement(forSt->initSt,
loopContext); // ignore init statement result
size_t iteration = 0;
while (true) // use while loop to simulate for loop, cause we
// need to check condition type every iteration
{
ObjectPtr condVal = eval(forSt->condition, loopContext);
if (condVal->getTypeInfo() != ValueType::Bool)
{
throw EvaluatorError(
u8"TypeError",
std::format("Condition must be boolean, but got '{}'", prettyType(condVal).toBasicString()),
forSt->condition);
}
if (!condVal->as<ValueType::BoolClass>()) { break; }
iteration++;
ContextPtr iterationContext = std::make_shared<Context>(
FString(std::format(
"<For {}:{}, Iteration {}>", forSt->getAAI().line, forSt->getAAI().column, iteration)),
loopContext); // every loop has its own context
StatementResult sr = evalBlockStatement(forSt->body, iterationContext);
if (sr.shouldReturn()) { return sr; }
if (sr.shouldBreak()) { break; }
if (sr.shouldContinue())
{
// continue to next iteration
continue;
}
evalStatement(forSt->incrementSt,
loopContext); // ignore increment statement result
}
return StatementResult::normal();
}
case TrySt: {
auto tryst = std::static_pointer_cast<Ast::TrySt>(stmt);
ContextPtr tryCtx = std::make_shared<Context>(
FString(std::format("<Try at {}:{}>", tryst->getAAI().line, tryst->getAAI().column)), ctx);
StatementResult sr = StatementResult::normal();
for (auto &stmt : tryst->body->stmts)
{
sr = evalStatement(stmt, tryCtx); // eval in try context
if (sr.isError()) { break; }
}
bool catched = false;
for (auto &cat : tryst->catches)
{
const FString &errVarName = cat.errVarName;
TypeInfo errVarType = (cat.hasType ? TypeInfo(cat.errVarType) : ValueType::Any);
if (isTypeMatch(errVarType, sr.result, ctx))
{
ContextPtr catchCtx = std::make_shared<Context>(
FString(
std::format("<Catch at {}:{}>", cat.body->getAAI().line, cat.body->getAAI().column)),
ctx);
catchCtx->def(errVarName, errVarType, AccessModifier::Normal, sr.result);
sr = evalBlockStatement(cat.body, catchCtx);
catched = true;
break;
}
}
if (!catched)
{
throw EvaluatorError(u8"UncaughtExceptionError",
std::format("Uncaught exception: {}", sr.result->toString().toBasicString()),
tryst);
}
if (tryst->finallyBlock) { sr = evalBlockStatement(tryst->finallyBlock, ctx); }
return sr;
}
case ThrowSt: {
auto ts = std::static_pointer_cast<Ast::ThrowSt>(stmt);
ObjectPtr value = eval(ts->value, ctx);
if (value->is<ValueType::NullClass>())
{
throw EvaluatorError(u8"TypeError", u8"Why did you throw a null?", ts);
}
return StatementResult::errorFlow(value);
}
case ReturnSt: {
auto returnSt = std::static_pointer_cast<Ast::ReturnSt>(stmt);
ObjectPtr returnValue = Object::getNullInstance(); // default is null
if (returnSt->retValue) returnValue = eval(returnSt->retValue, ctx);
return StatementResult::returnFlow(returnValue);
}
case BreakSt: {
if (!ctx->parent)
{
throw EvaluatorError(u8"BreakOutsideLoopError", u8"`break` statement outside loop", stmt);
}
if (!ctx->isInLoopContext())
{
throw EvaluatorError(u8"BreakOutsideLoopError", u8"`break` statement outside loop", stmt);
}
return StatementResult::breakFlow();
}
case ContinueSt: {
if (!ctx->parent)
{
throw EvaluatorError(u8"ContinueOutsideLoopError", u8"`continue` statement outside loop", stmt);
}
if (!ctx->isInLoopContext())
{
throw EvaluatorError(u8"ContinueOutsideLoopError", u8"`continue` statement outside loop", stmt);
}
return StatementResult::continueFlow();
}
case ExpressionStmt: {
auto exprStmt = std::static_pointer_cast<Ast::ExpressionStmtAst>(stmt);
return StatementResult::normal(eval(exprStmt->exp, ctx));
}
case BlockStatement: {
auto block = std::static_pointer_cast<Ast::BlockStatementAst>(stmt);
ContextPtr blockCtx = std::make_shared<Context>(
FString(std::format("<Block at {}:{}>", block->getAAI().line, block->getAAI().column)), ctx);
return evalBlockStatement(block, blockCtx);
}
default:
throw RuntimeError(
FString(std::format("Feature stmt {} unsupported yet", magic_enum::enum_name(stmt->getType()))));
}
}
};