修复了函数调用时求值类型使用的作用域错误的问题。结构体中现在可以使用自己

This commit is contained in:
2026-02-03 18:49:40 +08:00
parent 01c16dee3f
commit 4535f75058
9 changed files with 169 additions and 49 deletions

View File

@@ -0,0 +1,29 @@
import std.io;
import std.test;
var ascii_string_test := new test.Test{
"ascii_string_test",
func () => io.println("Hello," + " world!"),
2
};
var unicode_string_test := new test.Test{
"unicode_string_test",
func () => io.println("你好," + " 世界!"),
2
};
var unicode_string_inserting_test := new test.Test{
"unicode_string_inserting_test",
func (){
var str := "我是你的粑粑";
str.insert(1, "不");
return str;
},
"我不是你的粑粑"
};
var tests := [ascii_string_test, unicode_string_test, unicode_string_inserting_test];
var tester := new test.Tester{tests};
tester.TestAll();

View File

@@ -36,25 +36,13 @@ namespace Fig
std::unordered_map<Ast::Operator, UnaryOpFn> unOpRec;
std::unordered_map<Ast::Operator, BinaryOpFn> binOpRec;
bool hasUnaryOp(Ast::Operator op) const
{
return unOpRec.contains(op);
}
bool hasUnaryOp(Ast::Operator op) const { return unOpRec.contains(op); }
bool hasBinaryOp(Ast::Operator op) const
{
return binOpRec.contains(op);
}
bool hasBinaryOp(Ast::Operator op) const { return binOpRec.contains(op); }
const UnaryOpFn &getUnaryOpFn(Ast::Operator op) const
{
return unOpRec.at(op);
}
const UnaryOpFn &getUnaryOpFn(Ast::Operator op) const { return unOpRec.at(op); }
const BinaryOpFn &getBinaryOpFn(Ast::Operator op) const
{
return binOpRec.at(op);
}
const BinaryOpFn &getBinaryOpFn(Ast::Operator op) const { return binOpRec.at(op); }
};
class Context : public std::enable_shared_from_this<Context>
@@ -69,6 +57,7 @@ namespace Fig
// implRegistry <Struct, ordered list of ImplRecord>
std::unordered_map<TypeInfo, std::vector<ImplRecord>, TypeInfoHash> implRegistry;
std::unordered_map<TypeInfo, OperationRecord, TypeInfoHash> opRegistry;
public:
ContextPtr parent;
@@ -394,6 +383,8 @@ namespace Fig
throw ""; // ignore warning
}
std::unordered_map<TypeInfo, OperationRecord, TypeInfoHash> &getOpRegistry() { return opRegistry; }
bool hasOperatorImplemented(const TypeInfo &type, Ast::Operator op, bool isUnary = false) const
{
auto it = opRegistry.find(type);

View File

@@ -96,11 +96,11 @@ namespace Fig
size_t i;
for (i = 0; i < fnParas.posParas.size(); i++)
{
const TypeInfo &expectedType = actualType(eval(fnParas.posParas[i].second, ctx)); // look up type info, if exists a type
const TypeInfo &expectedType = actualType(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);
TypeInfo actualType = argVal->getTypeInfo();
if (!isTypeMatch(expectedType, argVal, ctx))
if (!isTypeMatch(expectedType, argVal, fn.closureContext))
{
throw EvaluatorError(u8"ArgumentTypeMismatchError",
std::format("In function '{}', argument '{}' expects type '{}', but got type '{}'",
@@ -116,10 +116,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, ctx));
const TypeInfo &expectedType = actualType(eval(fnParas.defParas[defParamIndex].second.first, fn.closureContext));
ObjectPtr defaultVal = eval(fnParas.defParas[defParamIndex].second.second, ctx);
if (!isTypeMatch(expectedType, defaultVal, ctx))
ObjectPtr defaultVal = eval(fnParas.defParas[defParamIndex].second.second, fn.closureContext);
if (!isTypeMatch(expectedType, defaultVal, fn.closureContext))
{
throw EvaluatorError(
u8"DefaultParameterTypeError",
@@ -134,7 +134,7 @@ namespace Fig
ObjectPtr argVal = eval(fnArgs.argv[i], ctx);
TypeInfo actualType = argVal->getTypeInfo();
if (!isTypeMatch(expectedType, argVal, ctx))
if (!isTypeMatch(expectedType, argVal, fn.closureContext))
{
throw EvaluatorError(u8"ArgumentTypeMismatchError",
std::format("In function '{}', argument '{}' expects type '{}', but got type '{}'",
@@ -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, ctx);
ObjectPtr defaultVal = eval(fnParas.defParas[defParamIndex].second.second, fn.closureContext);
evaluatedArgs.argv.push_back(defaultVal);
}
@@ -162,13 +162,13 @@ namespace Fig
if (j < fnParas.posParas.size())
{
paramName = fnParas.posParas[j].first;
paramType = actualType(eval(fnParas.posParas[j].second, ctx));
paramType = actualType(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, ctx));
paramType = actualType(eval(fnParas.defParas[defParamIndex].second.first, fn.closureContext));
}
AccessModifier argAm = AccessModifier::Normal;
newContext->def(paramName, paramType, argAm, evaluatedArgs.argv[j]);

View File

@@ -158,7 +158,7 @@ namespace Fig
};
ContextPtr instanceCtx =
std::make_shared<Context>(FString(std::format("<StructInstance {}>", structName.toBasicString())), ctx);
std::make_shared<Context>(FString(std::format("<StructInstance {}>", structName.toBasicString())), defContext);
/*
3 ways of calling constructor
.1 Person {"Fig", 1, "IDK"};

View File

@@ -8,6 +8,35 @@ namespace Fig
LvObject Evaluator::evalVarExpr(Ast::VarExpr var, ContextPtr ctx)
{
const FString &name = var->name;
// 调试信息
// std::cerr << "=== DEBUG evalVarExpr ===" << std::endl;
// std::cerr << "Looking for: " << name.toBasicString() << std::endl;
// std::cerr << "Context: " << ctx->getScopeName().toBasicString() << std::endl;
// // 打印上下文
// ContextPtr current = ctx;
// int depth = 0;
// while (current)
// {
// std::cerr << " [" << depth << "] " << current->getScopeName().toBasicString();
// if (current->containsInThisScope(name))
// {
// std::cerr << " -> FOUND HERE!" << std::endl;
// auto slot = current->get(name);
// std::cerr << " Type: " << slot->declaredType.toString().toBasicString() << std::endl;
// std::cerr << " Value: " << (slot->value ? slot->value->toString().toBasicString() : "null")
// << std::endl;
// }
// else
// {
// std::cerr << " -> not found" << std::endl;
// }
// current = current->parent;
// depth++;
// }
// end
if (!ctx->contains(name)) { throw EvaluatorError(u8"UndeclaredIdentifierError", name, var); }
return LvObject(ctx->get(name), ctx);
}
@@ -18,7 +47,26 @@ namespace Fig
const FString &member = me->member;
if (baseVal->getTypeInfo() == ValueType::Module)
{
// std::cerr << "=== DEBUG evalMemberExpr (Module) ===" << std::endl;
// std::cerr << "Module object: " << baseVal->toString().toBasicString() << std::endl;
const Module &mod = baseVal->as<Module>();
// std::cerr << "Module context: " << mod.ctx->getScopeName().toBasicString() << std::endl;
// std::cerr << "Looking for member: " << member.toBasicString() << std::endl;
// if (mod.ctx->contains(member))
// {
// std::cerr << "Found in module context!" << std::endl;
// if (mod.ctx->isVariablePublic(member)) { std::cerr << "And it's public!" << std::endl; }
// else
// {
// std::cerr << "But it's NOT public!" << std::endl;
// }
// }
// else
// {
// std::cerr << "NOT found in module context!" << std::endl;
// }
if (mod.ctx->contains(member) && mod.ctx->isVariablePublic(member))
{
return LvObject(mod.ctx->get(member), ctx);

View File

@@ -4,6 +4,7 @@
#include "Ast/functionParameters.hpp"
#include "Core/fig_string.hpp"
#include "Evaluator/Core/StatementResult.hpp"
#include "Evaluator/Value/Type.hpp"
#include "Evaluator/Value/value.hpp"
#include <Evaluator/Value/LvObject.hpp>
#include <Evaluator/evaluator.hpp>
@@ -103,6 +104,20 @@ namespace Fig
std::format("Structure '{}' already defined in this scope", stDef->name.toBasicString()),
stDef);
}
TypeInfo type(stDef->name, true); // register type name
ContextPtr defContext = std::make_shared<Context>(FString(std::format("<Struct {} at {}:{}>",
stDef->name.toBasicString(),
stDef->getAAI().line,
stDef->getAAI().column)),
ctx);
ObjectPtr structTypeObj = std::make_shared<Object>(StructType(type, defContext, {}));
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
std::vector<Field> fields;
std::vector<FString> _fieldNames;
for (Ast::StructDefField field : stDef->fields)
@@ -124,11 +139,8 @@ namespace Fig
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);
structTypeObj->as<StructType>().fields = fields;
const Ast::BlockStatement &body = stDef->body;
for (auto &st : body->stmts)
{
@@ -141,13 +153,6 @@ namespace Fig
}
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();
}

View File

@@ -1,3 +1,7 @@
#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>
@@ -7,6 +11,7 @@
#include <filesystem>
#include <fstream>
#include <memory>
#include <unordered_map>
#ifndef SourceInfo
#define SourceInfo(ptr) (ptr->sourcePath), (ptr->sourceLines)
@@ -34,20 +39,36 @@ namespace Fig
ContextPtr Evaluator::loadModule(const std::filesystem::path &path)
{
static std::unordered_map<FString, std::pair<std::vector<FString>, std::vector<Ast::AstBase>>> mod_ast_cache{};
FString modSourcePath(path.string());
std::ifstream file(path);
assert(file.is_open());
std::string source((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
file.close();
std::vector<FString> modSourceLines = Utils::splitSource(FString(source));
Lexer lexer((FString(source)), modSourcePath, modSourceLines);
Parser parser(lexer, modSourcePath, modSourceLines);
std::vector<Ast::AstBase> asts;
asts = parser.parseAll();
std::vector<FString> modSourceLines;
if (mod_ast_cache.contains(modSourcePath))
{
auto &[_sl, _asts] = mod_ast_cache[modSourcePath];
modSourceLines = _sl;
asts = _asts;
}
else
{
std::string source((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
file.close();
modSourceLines = Utils::splitSource(FString(source));
Lexer lexer((FString(source)), modSourcePath, modSourceLines);
Parser parser(lexer, modSourcePath, modSourceLines);
asts = parser.parseAll();
mod_ast_cache[modSourcePath] = {modSourceLines, asts};
}
Evaluator evaluator;
evaluator.SetSourcePath(modSourcePath);
@@ -77,6 +98,21 @@ namespace Fig
ctx->getImplRegistry().insert(modCtx->getImplRegistry().begin(), modCtx->getImplRegistry().end()); // load impl
for (auto &[type, opRecord] : modCtx->getOpRegistry())
{
if (ctx->getOpRegistry().contains(type))
{
throw EvaluatorError(
u8"DuplicateOperationOverload",
std::format("Module `{}` and current context `{}` have conflict operation overload for `{}` object",
modCtx->getScopeName().toBasicString(),
ctx->getScopeName().toBasicString(),
type.toString().toBasicString()),
i);
}
ctx->getOpRegistry()[type] = opRecord;
}
// std::cerr << modName.toBasicString() << '\n'; DEBUG
if (ctx->containsInThisScope(modName))

View File

@@ -1,6 +1,6 @@
/*
Official Module `std.tester`
Library/std/tester/tester.fig
Official Module `std.test`
Library/std/test/test.fig
Copyright © 2025 PuqiAR. All rights reserved.
*/

View File

@@ -43,6 +43,17 @@ public struct Time
return result;
}
// TODO: support `-` operator when Fig supports overload
// supported now! 26-2-2. PuqiAR
}
impl Operation for Time
{
Sub(l: Time, r: Time)
{
return new Time{
l.since(r)
};
}
}
public func now() -> Time