添加结构体组合, interface x : a + b {}

This commit is contained in:
2026-02-08 22:20:12 +08:00
parent 537011df32
commit 1dadaca4cc
6 changed files with 121 additions and 9 deletions

View File

@@ -0,0 +1,30 @@
import std.io;
struct Point
{
x: Int; // type specifiers are optional
y: Int; // type specifiers are optional
// x and y are private fields, can only reached by internal context
public func toString() -> String
{
return "(" + (x as String) + "," + (y as String) + ")";
}
// public func toString() {} is ok
}
// make points
var p1 := new Point{1, 2};
io.println(p1.toString()); // (1,2)
var p2 := new Point{x: 2, y: 3};
io.println(p2.toString()); // (2,3)
var x := 114;
var y := 514;
var p3 := new Point{y, x}; // shorthand mode, can be unordered, auto match field and variable!
// = Point{x: x, y: y}
io.println(p3.toString()); // (114,514)

View File

@@ -0,0 +1,2 @@
import std.io;

View File

@@ -35,10 +35,22 @@ namespace Fig::Ast
} }
}; };
/*
interface IO : Writable + Readable
{
}
interface XX
{
}
*/
class InterfaceDefAst final : public StatementAst class InterfaceDefAst final : public StatementAst
{ {
public: public:
FString name; FString name;
std::vector<Expression> bundles;
std::vector<InterfaceMethod> methods; std::vector<InterfaceMethod> methods;
std::vector<FString> parents; // Feature, NOT NOW std::vector<FString> parents; // Feature, NOT NOW
bool isPublic; bool isPublic;
@@ -48,8 +60,8 @@ namespace Fig::Ast
type = AstType::InterfaceDefSt; type = AstType::InterfaceDefSt;
} }
InterfaceDefAst(FString _name, std::vector<InterfaceMethod> _methods, bool _isPublic) : InterfaceDefAst(FString _name, std::vector<Expression> _bundles, std::vector<InterfaceMethod> _methods, bool _isPublic) :
name(std::move(_name)), methods(std::move(_methods)), isPublic(_isPublic) name(std::move(_name)), bundles(std::move(_bundles)), methods(std::move(_methods)), isPublic(_isPublic)
{ {
type = AstType::InterfaceDefSt; type = AstType::InterfaceDefSt;
} }

View File

@@ -183,9 +183,9 @@ namespace Fig
// we've checked argument count before, so here // we've checked argument count before, so here
// must be a default value // must be a default value
// evaluate default value in definition context // evaluate default value in definition context!
ObjectPtr defaultVal = check_unwrap(eval(field.defaultValue, ObjectPtr defaultVal = check_unwrap(eval(field.defaultValue,
ctx)); // it can't be null here defContext)); // it can't be null here
// type check // type check
if (!isTypeMatch(expectedType, defaultVal, ctx)) if (!isTypeMatch(expectedType, defaultVal, ctx))
@@ -345,13 +345,12 @@ namespace Fig
} }
} }
} }
ContextPtr stDefCtx = structT.defContext;
// load struct method // load struct method
for (auto &[id, fn] : stDefCtx->getFunctions()) for (auto &[id, fn] : defContext->getFunctions())
{ {
const FString &funcName = fn.name; const FString &funcName = fn.name;
const auto &funcSlot = stDefCtx->get(funcName); const auto &funcSlot = defContext->get(funcName);
instanceCtx->def(funcName, instanceCtx->def(funcName,
ValueType::Function, ValueType::Function,

View File

@@ -1,3 +1,4 @@
#include "Ast/Statements/InterfaceDefSt.hpp"
#include <Evaluator/Core/ExprResult.hpp> #include <Evaluator/Core/ExprResult.hpp>
#include <Ast/AccessModifier.hpp> #include <Ast/AccessModifier.hpp>
#include <Ast/Expressions/FunctionCall.hpp> #include <Ast/Expressions/FunctionCall.hpp>
@@ -14,6 +15,7 @@
#include <Utils/utils.hpp> #include <Utils/utils.hpp>
#include <unordered_map> #include <unordered_map>
#include <unordered_set>
namespace Fig namespace Fig
{ {
@@ -165,6 +167,7 @@ namespace Fig
auto ifd = std::static_pointer_cast<Ast::InterfaceDefAst>(stmt); auto ifd = std::static_pointer_cast<Ast::InterfaceDefAst>(stmt);
const FString &interfaceName = ifd->name; const FString &interfaceName = ifd->name;
const std::vector<Ast::Expression> &bundle_exprs = ifd->bundles;
if (ctx->containsInThisScope(interfaceName)) if (ctx->containsInThisScope(interfaceName))
{ {
@@ -173,11 +176,54 @@ namespace Fig
std::format("Interface `{}` already declared in this scope", interfaceName.toBasicString()), std::format("Interface `{}` already declared in this scope", interfaceName.toBasicString()),
ifd); ifd);
} }
std::vector<Ast::InterfaceMethod> bundle_methods;
std::unordered_map<FString, FString> cache_methods;
// K: interface method name V: method owner (interface)
for (const auto &exp : bundle_exprs)
{
ObjectPtr itf_val = check_unwrap_stres(eval(exp, ctx));
if (!itf_val->is<InterfaceType>())
{
throw EvaluatorError(
u8"TypeError",
std::format(
"Cannot bundle type '{}' that is not interface",
prettyType(itf_val).toBasicString()
),
exp
);
}
const InterfaceType &itfType = itf_val->as<InterfaceType>();
for (const auto &method : itfType.methods)
{
if (cache_methods.contains(method.name))
{
throw EvaluatorError(
u8"DuplicateInterfaceMethodError",
std::format(
"Interface `{}` has duplicate method '{}' with '{}.{}'",
itfType.type.toString().toBasicString(),
method.name.toBasicString(),
cache_methods[method.name].toBasicString(),
method.name.toBasicString()
),
ifd
);
}
cache_methods[method.name] = itfType.type.toString();
bundle_methods.push_back(method);
}
}
std::vector<Ast::InterfaceMethod> methods(ifd->methods);
methods.insert(methods.end(), bundle_methods.begin(), bundle_methods.end());
TypeInfo type(interfaceName, true); // register interface TypeInfo type(interfaceName, true); // register interface
ctx->def(interfaceName, ctx->def(interfaceName,
type, type,
(ifd->isPublic ? AccessModifier::PublicConst : AccessModifier::Const), (ifd->isPublic ? AccessModifier::PublicConst : AccessModifier::Const),
std::make_shared<Object>(InterfaceType(type, ifd->methods))); std::make_shared<Object>(InterfaceType(type, methods)));
return StatementResult::normal(); return StatementResult::normal();
} }

View File

@@ -386,6 +386,29 @@ namespace Fig
// entry: current is interface name // entry: current is interface name
FString interfaceName = currentToken().getValue(); FString interfaceName = currentToken().getValue();
next(); // consume name next(); // consume name
std::vector<Ast::Expression> bundles;
if (isThis(TokenType::Colon))
{
next(); // consume `:`
// parse bundle interfaces
if (isThis(TokenType::LeftBrace))
{
throwAddressableError<SyntaxError>(u8"expect interfaces to bundle");
}
while (true)
{
if (isThis(TokenType::LeftBrace)) { break; }
bundles.push_back(parseExpression(0, TokenType::Plus, TokenType::LeftBrace));
if (isThis(TokenType::Plus))
{
next(); // consume `+`
}
}
}
expect(TokenType::LeftBrace); // `{ expect(TokenType::LeftBrace); // `{
next(); // consume `{` next(); // consume `{`
@@ -427,7 +450,7 @@ namespace Fig
throwAddressableError<SyntaxError>(FString(u8"Invalid syntax"), currentAAI.line, currentAAI.column); throwAddressableError<SyntaxError>(FString(u8"Invalid syntax"), currentAAI.line, currentAAI.column);
} }
} }
return makeAst<Ast::InterfaceDefAst>(interfaceName, methods, isPublic); return makeAst<Ast::InterfaceDefAst>(interfaceName, bundles, methods, isPublic);
} }
Ast::Implement Parser::__parseImplement() Ast::Implement Parser::__parseImplement()